diff --git a/DEPS b/DEPS
index 9f57d975..2eecdd7 100644
--- a/DEPS
+++ b/DEPS
@@ -182,7 +182,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': 'cdc39bda92374df2ad50407229e25ad4c47cee90',
+  'skia_revision': 'ad56c4c143cf6f4cdc79cc129b2bc1d3093ce856',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -194,15 +194,15 @@
   # 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': '462e40f23b4db0e1d127c61ad32527cde028780d',
+  'angle_revision': 'be04c04729df41e359ebce625690af4368f12142',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '0711869b5f2097416c67811384fedbca3c025a00',
+  'swiftshader_revision': 'e3eb327e8c3c724a415fa4d5f4805f2e281f4760',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'de8ee4c6b0516d51ec262b6935a1afda0763430e',
+  'pdfium_revision': '6389dd16373131129808537a893c53817e5f7ca7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -245,7 +245,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '92c6c3ec3b9bd8c5bd2182c62b0f6c2cfaabbad9',
+  'catapult_revision': '69b4144bb101fbdfdda6ffb5257e89a3f28cb1cb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -253,7 +253,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': '9de6dbb0abd9f5c79fb2850eeabafa2e0ae81904',
+  'devtools_frontend_revision': '597115926cf7d0a1fcdfc71df0521fe74e99ff8a',
   # 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.
@@ -289,7 +289,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.
-  'spv_tools_revision': '636f449e1529a10d259eb7dc37d97192cf2820f8',
+  'spv_tools_revision': '74130f2d3ab1b97c9fc042d8e7822a362a4cadb6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -305,11 +305,11 @@
   # 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': '783cd5a79c8ada83622c327ec054f6cc990c2825',
+  'dawn_revision': '45aed839e9c5647375bbc0249cc1b298f53ad190',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'quiche_revision': 'd7b17f31c55ae26b2688aa6f34a979d5312fa7e9',
+  'quiche_revision': '1a5d09ce1b898b4a7a694f5ae99a9a9a31bd34f3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ios_webkit
   # and whatever else without interference from each other.
@@ -652,7 +652,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/android_protoc',
-              'version': 'k9khK3dY-WuKXtL8tfQRcsvo2H1qS6C4-G5ckDZ4yyMC',
+              'version': 'jtrjlp1zR2hubDA9R5NKk4GwXfuuRhoXts7tgjevxDMC',
           },
       ],
       'condition': 'checkout_android',
@@ -811,7 +811,7 @@
   },
 
   'src/third_party/breakpad/breakpad':
-    Var('chromium_git') + '/breakpad/breakpad.git' + '@' + '2ffe116322aa4373d408a72b665fa7fe7a504d4a',
+    Var('chromium_git') + '/breakpad/breakpad.git' + '@' + '2757a2c9c819fcae3784576aef0c8400c7ad06d7',
 
   'src/third_party/byte_buddy': {
       'packages': [
@@ -855,7 +855,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '93c0a8991c77849614f98e75410921d08c00db86',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '1049ade3e12f40c07a8847036a60e12138058f78',
       'condition': 'checkout_linux',
   },
 
@@ -875,7 +875,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '88b4a168c3427153a4a00d21f1f01736afc6d88b',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'd27e40cf55af8f1aa2068bc425c6a7c616ea9db7',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1224,7 +1224,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '4a3f9b801b02ec9bd0b137c72caf0cc7bb898f6d',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'bc9475ac0bf57ff18e9fea4fc10b6e3eb8f09247',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1302,7 +1302,7 @@
       'packages': [
           {
               'package': 'fuchsia/third_party/aemu/linux-amd64',
-              'version': 'ij0nEFLmrqJqEp81i5YIDjeQ8epXhPrtAI0otT1OId0C'
+              'version': 'WCiGqc2IsqMVCcj8UruU8vGLvhfosP46CB3tAy6N2boC'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
@@ -1452,7 +1452,7 @@
   },
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '8b7cfa16aa2f07a5cd41ed3c7e1ae975a2b8d1f2',
+    Var('webrtc_git') + '/src.git' + '@' + '8e75bd40e04742bc8e4bf3ed36c2eafbfa0858ad',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1524,7 +1524,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@14793b02f904e916fd0f23b210d274834bf833ae',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@73c5db6dfb0ce532882a6fc83f9232ce1cd1f6c7',
     'condition': 'checkout_src_internal',
   },
 
@@ -1532,7 +1532,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'voJICdrAJXQHr-PwOYa17rQCqEsW2U1T1672WgefrioC',
+        'version': 'zqEjsRuI2qX11reJI5f9bE5X3iD6CtglpDcv2Cugj3cC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3321,7 +3321,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_protobuf_protobuf_javalite',
-              'version': 'version:3.11.4-cr0',
+              'version': 'version:3.12.2-cr0',
           },
       ],
       'condition': 'checkout_android',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index b0be16e..f78b8eec 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -1296,11 +1296,26 @@
 )
 
 
+# These are not checked on the public chromium-presubmit trybot.
+# Add files here that rely on .py files that exists only for target_os="android"
+# checkouts (e.g. //third_party/catapult).
 _ANDROID_SPECIFIC_PYDEPS_FILES = [
     'android_webview/tools/run_cts.pydeps',
+    'build/android/devil_chromium.pydeps',
+    'build/android/gyp/create_bundle_wrapper_script.pydeps',
+    'build/android/gyp/jinja_template.pydeps',
+    'build/android/resource_sizes.pydeps',
+    'build/android/test_runner.pydeps',
+    'build/android/test_wrapper/logdog_wrapper.pydeps',
+    'chrome/android/features/create_stripped_java_factory.pydeps',
+    'testing/scripts/run_android_wpt.pydeps',
+    'third_party/android_platform/development/scripts/stack.pydeps',
+]
+
+
+_GENERIC_PYDEPS_FILES = [
     'base/android/jni_generator/jni_generator.pydeps',
     'base/android/jni_generator/jni_registration_generator.pydeps',
-    'build/android/devil_chromium.pydeps',
     'build/android/gyp/aar.pydeps',
     'build/android/gyp/aidl.pydeps',
     'build/android/gyp/allot_native_libraries.pydeps',
@@ -1313,7 +1328,6 @@
     'build/android/gyp/create_apk_operations_script.pydeps',
     'build/android/gyp/create_app_bundle_apks.pydeps',
     'build/android/gyp/create_app_bundle.pydeps',
-    'build/android/gyp/create_bundle_wrapper_script.pydeps',
     'build/android/gyp/create_java_binary_script.pydeps',
     'build/android/gyp/create_size_info_files.pydeps',
     'build/android/gyp/desugar.pydeps',
@@ -1329,7 +1343,6 @@
     'build/android/gyp/java_cpp_enum.pydeps',
     'build/android/gyp/java_cpp_strings.pydeps',
     'build/android/gyp/jetify_jar.pydeps',
-    'build/android/gyp/jinja_template.pydeps',
     'build/android/gyp/lint.pydeps',
     'build/android/gyp/main_dex_list.pydeps',
     'build/android/gyp/merge_manifest.pydeps',
@@ -1342,21 +1355,11 @@
     'build/android/gyp/zip.pydeps',
     'build/android/incremental_install/generate_android_manifest.pydeps',
     'build/android/incremental_install/write_installer_json.pydeps',
-    'build/android/resource_sizes.pydeps',
-    'build/android/test_runner.pydeps',
-    'build/android/test_wrapper/logdog_wrapper.pydeps',
     'build/protoc_java.pydeps',
-    'chrome/android/features/create_stripped_java_factory.pydeps',
-    'components/module_installer/android/module_desc_java.pydeps',
-    'net/tools/testserver/testserver.pydeps',
-    'testing/scripts/run_android_wpt.pydeps',
-    'third_party/android_platform/development/scripts/stack.pydeps',
-]
-
-
-_GENERIC_PYDEPS_FILES = [
     'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
     'chrome/test/chromedriver/test/run_py_tests.pydeps',
+    'components/module_installer/android/module_desc_java.pydeps',
+    'net/tools/testserver/testserver.pydeps',
     'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
     'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
     'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
@@ -3643,7 +3646,8 @@
       # subrepositories. We can't figure out which files change, so re-check
       # all files.
       # Changes to print_python_deps.py affect all .pydeps.
-      if local_path == 'DEPS' or local_path.endswith('print_python_deps.py'):
+      if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
+          'print_python_deps.py'):
         return self._pydeps_files
       elif local_path.endswith('.pydeps'):
         if local_path in self._pydeps_files:
diff --git a/android_webview/browser/aw_browser_process.cc b/android_webview/browser/aw_browser_process.cc
index d6ab5d0..b1c4f895 100644
--- a/android_webview/browser/aw_browser_process.cc
+++ b/android_webview/browser/aw_browser_process.cc
@@ -5,6 +5,7 @@
 #include "android_webview/browser/aw_browser_process.h"
 
 #include "android_webview/browser/aw_browser_context.h"
+#include "android_webview/browser/metrics/visibility_metrics_logger.h"
 #include "base/base_paths_posix.h"
 #include "base/path_service.h"
 #include "base/task/thread_pool.h"
@@ -76,6 +77,12 @@
   return browser_policy_connector_.get();
 }
 
+VisibilityMetricsLogger* AwBrowserProcess::visibility_metrics_logger() {
+  if (!visibility_metrics_logger_)
+    visibility_metrics_logger_ = std::make_unique<VisibilityMetricsLogger>();
+  return visibility_metrics_logger_.get();
+}
+
 void AwBrowserProcess::CreateBrowserPolicyConnector() {
   DCHECK(!browser_policy_connector_);
 
diff --git a/android_webview/browser/aw_browser_process.h b/android_webview/browser/aw_browser_process.h
index 2a3e321..0fbe92e 100644
--- a/android_webview/browser/aw_browser_process.h
+++ b/android_webview/browser/aw_browser_process.h
@@ -30,6 +30,8 @@
 
 }  // namespace prefs
 
+class VisibilityMetricsLogger;
+
 class AwBrowserProcess {
  public:
   AwBrowserProcess(AwFeatureListCreator* aw_feature_list_creator);
@@ -39,6 +41,7 @@
 
   PrefService* local_state();
   AwBrowserPolicyConnector* browser_policy_connector();
+  VisibilityMetricsLogger* visibility_metrics_logger();
 
   void CreateBrowserPolicyConnector();
   void CreateLocalState();
@@ -99,6 +102,8 @@
   std::unique_ptr<AwSafeBrowsingWhitelistManager>
       safe_browsing_whitelist_manager_;
 
+  std::unique_ptr<VisibilityMetricsLogger> visibility_metrics_logger_;
+
   DISALLOW_COPY_AND_ASSIGN(AwBrowserProcess);
 };
 
diff --git a/android_webview/browser/aw_contents.cc b/android_webview/browser/aw_contents.cc
index 897f9dfc..64254d3 100644
--- a/android_webview/browser/aw_contents.cc
+++ b/android_webview/browser/aw_contents.cc
@@ -247,6 +247,7 @@
   content::SynchronousCompositor::SetClientForWebContents(
       web_contents_.get(), &browser_view_renderer_);
   AwContentsLifecycleNotifier::GetInstance().OnWebViewCreated(this);
+  AwBrowserProcess::GetInstance()->visibility_metrics_logger()->AddClient(this);
 }
 
 void AwContents::SetJavaPeers(
@@ -350,6 +351,8 @@
   }
   browser_view_renderer_.SetCurrentCompositorFrameConsumer(nullptr);
   AwContentsLifecycleNotifier::GetInstance().OnWebViewDestroyed(this);
+  AwBrowserProcess::GetInstance()->visibility_metrics_logger()->RemoveClient(
+      this);
 }
 
 base::android::ScopedJavaLocalRef<jobject> AwContents::GetWebContents(
@@ -916,6 +919,9 @@
   web_contents_->GetNativeView()->OnPhysicalBackingSizeChanged(size);
   web_contents_->GetNativeView()->OnSizeChanged(w, h);
   browser_view_renderer_.OnSizeChanged(w, h);
+  AwBrowserProcess::GetInstance()
+      ->visibility_metrics_logger()
+      ->ClientVisibilityChanged(this);
 }
 
 void AwContents::SetViewVisibility(JNIEnv* env,
@@ -923,6 +929,9 @@
                                    bool visible) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   browser_view_renderer_.SetViewVisibility(visible);
+  AwBrowserProcess::GetInstance()
+      ->visibility_metrics_logger()
+      ->ClientVisibilityChanged(this);
 }
 
 void AwContents::SetWindowVisibility(JNIEnv* env,
@@ -934,6 +943,9 @@
     AwContentsLifecycleNotifier::GetInstance().OnWebViewWindowBeVisible(this);
   else
     AwContentsLifecycleNotifier::GetInstance().OnWebViewWindowBeInvisible(this);
+  AwBrowserProcess::GetInstance()
+      ->visibility_metrics_logger()
+      ->ClientVisibilityChanged(this);
 }
 
 void AwContents::SetIsPaused(JNIEnv* env,
@@ -950,6 +962,9 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   browser_view_renderer_.OnAttachedToWindow(w, h);
   AwContentsLifecycleNotifier::GetInstance().OnWebViewAttachedToWindow(this);
+  AwBrowserProcess::GetInstance()
+      ->visibility_metrics_logger()
+      ->ClientVisibilityChanged(this);
 }
 
 void AwContents::OnDetachedFromWindow(JNIEnv* env,
@@ -957,6 +972,9 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   browser_view_renderer_.OnDetachedFromWindow();
   AwContentsLifecycleNotifier::GetInstance().OnWebViewDetachedFromWindow(this);
+  AwBrowserProcess::GetInstance()
+      ->visibility_metrics_logger()
+      ->ClientVisibilityChanged(this);
 }
 
 bool AwContents::IsVisible(JNIEnv* env, const JavaParamRef<jobject>& obj) {
@@ -1490,6 +1508,13 @@
   return Java_AwContents_getErrorUiType(env, obj);
 }
 
+VisibilityMetricsLogger::VisibilityInfo AwContents::GetVisibilityInfo() {
+  return VisibilityMetricsLogger::VisibilityInfo{
+      browser_view_renderer_.attached_to_window(),
+      browser_view_renderer_.view_visible(),
+      browser_view_renderer_.window_visible()};
+}
+
 void AwContents::RendererUnresponsive(
     content::RenderProcessHost* render_process_host) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/android_webview/browser/aw_contents.h b/android_webview/browser/aw_contents.h
index 316b7a9..df492ed8 100644
--- a/android_webview/browser/aw_contents.h
+++ b/android_webview/browser/aw_contents.h
@@ -17,6 +17,7 @@
 #include "android_webview/browser/gfx/browser_view_renderer_client.h"
 #include "android_webview/browser/icon_helper.h"
 #include "android_webview/browser/js_java_interaction/js_java_configurator_host.h"
+#include "android_webview/browser/metrics/visibility_metrics_logger.h"
 #include "android_webview/browser/permission/permission_request_handler_client.h"
 #include "android_webview/browser/renderer_host/aw_render_view_host_ext.h"
 #include "android_webview/browser/safe_browsing/aw_safe_browsing_ui_manager.h"
@@ -61,7 +62,8 @@
                    public AwBrowserPermissionRequestDelegate,
                    public AwRenderProcessGoneDelegate,
                    public content::WebContentsObserver,
-                   public AwSafeBrowsingUIManager::UIManagerClient {
+                   public AwSafeBrowsingUIManager::UIManagerClient,
+                   public VisibilityMetricsLogger::Client {
  public:
   // Returns the AwContents instance associated with |web_contents|, or NULL.
   static AwContents* FromWebContents(content::WebContents* web_contents);
@@ -396,6 +398,9 @@
   bool CanShowInterstitial() override;
   int GetErrorUiType() override;
 
+  // VisibilityMetricsLogger::Client implementation
+  VisibilityMetricsLogger::VisibilityInfo GetVisibilityInfo() override;
+
   // AwRenderProcessGoneDelegate overrides
   RenderProcessGoneResult OnRenderProcessGone(int child_process_id,
                                               bool crashed) override;
diff --git a/android_webview/browser/aw_metrics_service_client_delegate.cc b/android_webview/browser/aw_metrics_service_client_delegate.cc
index 0824a81..3ac28dd 100644
--- a/android_webview/browser/aw_metrics_service_client_delegate.cc
+++ b/android_webview/browser/aw_metrics_service_client_delegate.cc
@@ -4,7 +4,9 @@
 
 #include "android_webview/browser/aw_metrics_service_client_delegate.h"
 
+#include "android_webview/browser/aw_browser_process.h"
 #include "android_webview/browser/lifecycle/aw_contents_lifecycle_notifier.h"
+#include "android_webview/browser/metrics/visibility_metrics_provider.h"
 #include "android_webview/browser/page_load_metrics/aw_page_load_metrics_provider.h"
 #include "components/metrics/metrics_service.h"
 
@@ -16,7 +18,9 @@
 void AwMetricsServiceClientDelegate::RegisterAdditionalMetricsProviders(
     metrics::MetricsService* service) {
   service->RegisterMetricsProvider(
-      std::make_unique<android_webview::AwPageLoadMetricsProvider>());
+      std::make_unique<AwPageLoadMetricsProvider>());
+  service->RegisterMetricsProvider(std::make_unique<VisibilityMetricsProvider>(
+      AwBrowserProcess::GetInstance()->visibility_metrics_logger()));
 }
 
 void AwMetricsServiceClientDelegate::AddWebViewAppStateObserver(
diff --git a/android_webview/browser/find_helper.cc b/android_webview/browser/find_helper.cc
index c50b2d57..f720aa58 100644
--- a/android_webview/browser/find_helper.cc
+++ b/android_webview/browser/find_helper.cc
@@ -45,7 +45,7 @@
   auto options = blink::mojom::FindOptions::New();
   options->forward = true;
   options->match_case = false;
-  options->find_next = false;
+  options->new_session = true;
 
   web_contents()->Find(current_request_id_, search_string, std::move(options));
 }
@@ -72,7 +72,7 @@
   auto options = blink::mojom::FindOptions::New();
   options->forward = forward;
   options->match_case = false;
-  options->find_next = true;
+  options->new_session = false;
 
   web_contents()->Find(current_request_id_, last_search_string_,
                        std::move(options));
diff --git a/android_webview/browser/gfx/browser_view_renderer.h b/android_webview/browser/gfx/browser_view_renderer.h
index bf716fd..951ec6c 100644
--- a/android_webview/browser/gfx/browser_view_renderer.h
+++ b/android_webview/browser/gfx/browser_view_renderer.h
@@ -116,6 +116,8 @@
   // Android views hierarchy gluing.
   bool IsVisible() const;
   gfx::Rect GetScreenRect() const;
+  bool view_visible() const { return view_visible_; }
+  bool window_visible() const { return window_visible_; }
   bool attached_to_window() const { return attached_to_window_; }
   bool was_attached() const { return was_attached_; }
   gfx::Size size() const { return size_; }
diff --git a/android_webview/browser/metrics/BUILD.gn b/android_webview/browser/metrics/BUILD.gn
index c261087..ba3c9e0 100644
--- a/android_webview/browser/metrics/BUILD.gn
+++ b/android_webview/browser/metrics/BUILD.gn
@@ -8,6 +8,10 @@
     "aw_metrics_service_client.h",
     "aw_stability_metrics_provider.cc",
     "aw_stability_metrics_provider.h",
+    "visibility_metrics_logger.cc",
+    "visibility_metrics_logger.h",
+    "visibility_metrics_provider.cc",
+    "visibility_metrics_provider.h",
   ]
   deps = [
     "//android_webview:browser_jni_headers",
diff --git a/android_webview/browser/metrics/visibility_metrics_logger.cc b/android_webview/browser/metrics/visibility_metrics_logger.cc
new file mode 100644
index 0000000..817ffe6
--- /dev/null
+++ b/android_webview/browser/metrics/visibility_metrics_logger.cc
@@ -0,0 +1,159 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "android_webview/browser/metrics/visibility_metrics_logger.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "base/no_destructor.h"
+#include "base/rand_util.h"
+#include "base/time/time.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+
+using base::NoDestructor;
+using content::BrowserThread;
+
+namespace android_webview {
+
+base::HistogramBase* VisibilityMetricsLogger::GetGlobalVisibilityHistogram() {
+  static NoDestructor<base::HistogramBase*> histogram(
+      base::Histogram::FactoryGet(
+          "Android.WebView.Visibility.Global", 1,
+          static_cast<int>(VisibilityMetricsLogger::Visibility::kCount),
+          static_cast<int>(VisibilityMetricsLogger::Visibility::kCount) + 1,
+          base::HistogramBase::kUmaTargetedHistogramFlag));
+  return *histogram;
+}
+
+base::HistogramBase*
+VisibilityMetricsLogger::GetPerWebViewVisibilityHistogram() {
+  static NoDestructor<base::HistogramBase*> histogram(
+      base::Histogram::FactoryGet(
+          "Android.WebView.Visibility.PerWebView", 1,
+          static_cast<int>(VisibilityMetricsLogger::Visibility::kCount),
+          static_cast<int>(VisibilityMetricsLogger::Visibility::kCount) + 1,
+          base::HistogramBase::kUmaTargetedHistogramFlag));
+  return *histogram;
+}
+
+VisibilityMetricsLogger::VisibilityMetricsLogger() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  last_update_time_ = base::TimeTicks::Now();
+}
+
+VisibilityMetricsLogger::~VisibilityMetricsLogger() = default;
+
+void VisibilityMetricsLogger::AddClient(Client* client) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(client_visibility_.find(client) == client_visibility_.end());
+
+  UpdateDurations(base::TimeTicks::Now());
+
+  client_visibility_[client] = VisibilityInfo();
+  ProcessClientUpdate(client, client->GetVisibilityInfo());
+}
+
+void VisibilityMetricsLogger::RemoveClient(Client* client) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(client_visibility_.find(client) != client_visibility_.end());
+
+  UpdateDurations(base::TimeTicks::Now());
+
+  ProcessClientUpdate(client, VisibilityInfo());
+  client_visibility_.erase(client);
+}
+
+void VisibilityMetricsLogger::ClientVisibilityChanged(Client* client) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(client_visibility_.find(client) != client_visibility_.end());
+
+  UpdateDurations(base::TimeTicks::Now());
+
+  ProcessClientUpdate(client, client->GetVisibilityInfo());
+}
+
+void VisibilityMetricsLogger::UpdateDurations(base::TimeTicks update_time) {
+  base::AutoLock lock(duration_lock_);
+
+  base::TimeDelta delta = update_time - last_update_time_;
+  if (visible_client_count_ > 0) {
+    any_webview_visible_duration_ += delta;
+  } else {
+    no_webview_visible_duration_ += delta;
+  }
+  total_webview_visible_duration_ += delta * visible_client_count_;
+  total_webview_hidden_duration_ +=
+      delta * (client_visibility_.size() - visible_client_count_);
+
+  last_update_time_ = update_time;
+}
+
+bool VisibilityMetricsLogger::IsVisible(const VisibilityInfo& info) {
+  return info.view_attached && info.view_visible && info.window_visible;
+}
+
+void VisibilityMetricsLogger::ProcessClientUpdate(Client* client,
+                                                  const VisibilityInfo& info) {
+  VisibilityInfo curr_info = client_visibility_[client];
+  bool was_visible = IsVisible(curr_info);
+  bool is_visible = IsVisible(info);
+  client_visibility_[client] = info;
+
+  DCHECK(!was_visible || visible_client_count_ > 0);
+  if (!was_visible && is_visible) {
+    ++visible_client_count_;
+  } else if (was_visible && !is_visible) {
+    --visible_client_count_;
+  }
+}
+
+void VisibilityMetricsLogger::RecordMetrics() {
+  UpdateDurations(base::TimeTicks::Now());
+
+  int32_t any_webview_visible_seconds;
+  int32_t no_webview_visible_seconds;
+  int32_t total_webview_visible_seconds;
+  int32_t total_webview_hidden_seconds;
+
+  {
+    base::AutoLock lock(duration_lock_);
+
+    any_webview_visible_seconds = any_webview_visible_duration_.InSeconds();
+    any_webview_visible_duration_ -=
+        base::TimeDelta::FromSeconds(any_webview_visible_seconds);
+
+    no_webview_visible_seconds = no_webview_visible_duration_.InSeconds();
+    no_webview_visible_duration_ -=
+        base::TimeDelta::FromSeconds(no_webview_visible_seconds);
+
+    total_webview_visible_seconds = total_webview_visible_duration_.InSeconds();
+    total_webview_visible_duration_ -=
+        base::TimeDelta::FromSeconds(total_webview_visible_seconds);
+
+    total_webview_hidden_seconds = total_webview_hidden_duration_.InSeconds();
+    total_webview_hidden_duration_ -=
+        base::TimeDelta::FromSeconds(total_webview_hidden_seconds);
+  }
+
+  if (any_webview_visible_seconds) {
+    GetGlobalVisibilityHistogram()->AddCount(
+        static_cast<int>(Visibility::kVisible), any_webview_visible_seconds);
+  }
+  if (no_webview_visible_seconds) {
+    GetGlobalVisibilityHistogram()->AddCount(
+        static_cast<int>(Visibility::kNotVisible), no_webview_visible_seconds);
+  }
+
+  if (total_webview_visible_seconds) {
+    GetPerWebViewVisibilityHistogram()->AddCount(
+        static_cast<int>(Visibility::kVisible), total_webview_visible_seconds);
+  }
+  if (total_webview_hidden_seconds) {
+    GetPerWebViewVisibilityHistogram()->AddCount(
+        static_cast<int>(Visibility::kNotVisible),
+        total_webview_hidden_seconds);
+  }
+}
+
+}  // namespace android_webview
\ No newline at end of file
diff --git a/android_webview/browser/metrics/visibility_metrics_logger.h b/android_webview/browser/metrics/visibility_metrics_logger.h
new file mode 100644
index 0000000..4aa0cdb
--- /dev/null
+++ b/android_webview/browser/metrics/visibility_metrics_logger.h
@@ -0,0 +1,79 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ANDROID_WEBVIEW_BROWSER_METRICS_VISIBILITY_METRICS_LOGGER_H_
+#define ANDROID_WEBVIEW_BROWSER_METRICS_VISIBILITY_METRICS_LOGGER_H_
+
+#include <map>
+
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class HistogramBase;
+
+}  // namespace base
+
+namespace android_webview {
+
+class VisibilityMetricsLogger {
+ public:
+  struct VisibilityInfo {
+    bool view_attached = false;
+    bool view_visible = false;
+    bool window_visible = false;
+  };
+
+  enum class Visibility { kVisible = 0, kNotVisible = 1, kCount = 2 };
+
+  class Client {
+   public:
+    virtual VisibilityInfo GetVisibilityInfo() = 0;
+  };
+
+  VisibilityMetricsLogger();
+  virtual ~VisibilityMetricsLogger();
+
+  VisibilityMetricsLogger(const VisibilityMetricsLogger&) = delete;
+  VisibilityMetricsLogger& operator=(const VisibilityMetricsLogger&) = delete;
+
+  void AddClient(Client* client);
+  void RemoveClient(Client* client);
+  void ClientVisibilityChanged(Client* client);
+
+  void RecordMetrics();
+
+ private:
+  static base::HistogramBase* GetGlobalVisibilityHistogram();
+  static base::HistogramBase* GetPerWebViewVisibilityHistogram();
+
+  void UpdateDurations(base::TimeTicks update_time);
+  void ProcessClientUpdate(Client* client, const VisibilityInfo& info);
+  bool IsVisible(const VisibilityInfo& info);
+
+  // Current number of visible webviews.
+  size_t visible_client_count_ = 0;
+
+  base::Lock duration_lock_;
+  // Duration for which any webview was visible.
+  base::TimeDelta any_webview_visible_duration_ GUARDED_BY(duration_lock_) =
+      base::TimeDelta::FromSeconds(0);
+  // Duration for which no webviews were visible.
+  base::TimeDelta no_webview_visible_duration_ GUARDED_BY(duration_lock_) =
+      base::TimeDelta::FromSeconds(0);
+  // Total duration for which all webviews were visible.
+  base::TimeDelta total_webview_visible_duration_ GUARDED_BY(duration_lock_) =
+      base::TimeDelta::FromSeconds(0);
+  // Total duration for which all webviews were not visible.
+  base::TimeDelta total_webview_hidden_duration_ GUARDED_BY(duration_lock_) =
+      base::TimeDelta::FromSeconds(0);
+
+  base::TimeTicks last_update_time_;
+  std::map<Client*, VisibilityInfo> client_visibility_;
+};
+
+}  // namespace android_webview
+
+#endif  // ANDROID_WEBVIEW_BROWSER_METRICS_VISIBILITY_METRICS_LOGGER_H_
diff --git a/android_webview/browser/metrics/visibility_metrics_logger_unittest.cc b/android_webview/browser/metrics/visibility_metrics_logger_unittest.cc
new file mode 100644
index 0000000..21c524f2
--- /dev/null
+++ b/android_webview/browser/metrics/visibility_metrics_logger_unittest.cc
@@ -0,0 +1,238 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "android_webview/browser/metrics/visibility_metrics_logger.h"
+
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/task_environment.h"
+#include "base/time/clock.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace android_webview {
+
+static const base::TickClock* g_clock;
+
+class TestClient : public VisibilityMetricsLogger::Client {
+ public:
+  explicit TestClient(VisibilityMetricsLogger* logger) : logger_(logger) {
+    logger_->AddClient(this);
+  }
+
+  virtual ~TestClient() { logger_->RemoveClient(this); }
+
+  void SetViewAttached(bool view_attached) {
+    visibility_info_.view_attached = view_attached;
+    logger_->ClientVisibilityChanged(this);
+  }
+
+  void SetViewVisible(bool view_visible) {
+    visibility_info_.view_visible = view_visible;
+    logger_->ClientVisibilityChanged(this);
+  }
+
+  void SetWindowVisible(bool window_visible) {
+    visibility_info_.window_visible = window_visible;
+    logger_->ClientVisibilityChanged(this);
+  }
+
+  // VisibilityMetricsLogger::Client implementation
+  VisibilityMetricsLogger::VisibilityInfo GetVisibilityInfo() override {
+    return visibility_info_;
+  }
+
+ private:
+  VisibilityMetricsLogger* logger_;
+  VisibilityMetricsLogger::VisibilityInfo visibility_info_;
+};
+
+class VisibilityMetricsLoggerTest : public testing::Test {
+ public:
+  VisibilityMetricsLoggerTest()
+      : task_environment_(
+            content::BrowserTaskEnvironment::TimeSource::MOCK_TIME) {
+    g_clock = task_environment_.GetMockTickClock();
+  }
+
+  ~VisibilityMetricsLoggerTest() override { g_clock = nullptr; }
+
+  VisibilityMetricsLogger* logger() { return logger_.get(); }
+
+  content::BrowserTaskEnvironment& task_environment() {
+    return task_environment_;
+  }
+
+ protected:
+  // testing::Test.
+  void SetUp() override {
+    logger_ = std::make_unique<VisibilityMetricsLogger>();
+  }
+
+  void TearDown() override {}
+
+ private:
+  content::BrowserTaskEnvironment task_environment_;
+  std::unique_ptr<VisibilityMetricsLogger> logger_;
+};
+
+TEST_F(VisibilityMetricsLoggerTest, TestFractionalSecondAccumulation) {
+  base::HistogramTester histogram_tester;
+
+  std::unique_ptr<TestClient> client = std::make_unique<TestClient>(logger());
+  client->SetViewVisible(true);
+  client->SetViewAttached(true);
+  client->SetWindowVisible(true);
+
+  task_environment().FastForwardBy(base::TimeDelta::FromMilliseconds(500));
+
+  logger()->RecordMetrics();
+  histogram_tester.ExpectBucketCount(
+      "Android.WebView.Visibility.Global",
+      VisibilityMetricsLogger::Visibility::kVisible, 0);
+
+  task_environment().FastForwardBy(base::TimeDelta::FromMilliseconds(500));
+
+  logger()->RecordMetrics();
+  histogram_tester.ExpectBucketCount(
+      "Android.WebView.Visibility.Global",
+      VisibilityMetricsLogger::Visibility::kVisible, 1);
+
+  client.reset();
+}
+
+TEST_F(VisibilityMetricsLoggerTest, TestSingleVisibleClient) {
+  base::HistogramTester histogram_tester;
+
+  task_environment().FastForwardBy(base::TimeDelta::FromSeconds(10));
+  std::unique_ptr<TestClient> client = std::make_unique<TestClient>(logger());
+
+  task_environment().FastForwardBy(base::TimeDelta::FromSeconds(30));
+  client->SetViewVisible(true);
+  client->SetViewAttached(true);
+  client->SetWindowVisible(true);
+
+  task_environment().FastForwardBy(base::TimeDelta::FromSeconds(10));
+  client->SetWindowVisible(false);
+
+  logger()->RecordMetrics();
+  histogram_tester.ExpectBucketCount(
+      "Android.WebView.Visibility.Global",
+      VisibilityMetricsLogger::Visibility::kVisible, 10);
+  histogram_tester.ExpectBucketCount(
+      "Android.WebView.Visibility.Global",
+      VisibilityMetricsLogger::Visibility::kNotVisible, 40);
+
+  client->SetViewVisible(true);
+  client->SetViewAttached(true);
+  client->SetWindowVisible(true);
+  task_environment().FastForwardBy(base::TimeDelta::FromSeconds(90));
+
+  logger()->RecordMetrics();
+  histogram_tester.ExpectBucketCount(
+      "Android.WebView.Visibility.Global",
+      VisibilityMetricsLogger::Visibility::kVisible, 100);
+  histogram_tester.ExpectBucketCount(
+      "Android.WebView.Visibility.Global",
+      VisibilityMetricsLogger::Visibility::kNotVisible, 40);
+
+  client.reset();
+}
+
+TEST_F(VisibilityMetricsLoggerTest, TestLongDurationVisibleClient) {
+  base::HistogramTester histogram_tester;
+  std::unique_ptr<TestClient> client1 = std::make_unique<TestClient>(logger());
+  std::unique_ptr<TestClient> client2 = std::make_unique<TestClient>(logger());
+
+  task_environment().FastForwardBy(base::TimeDelta::FromSeconds(300));
+  client1->SetViewVisible(true);
+  client1->SetViewAttached(true);
+  client1->SetWindowVisible(true);
+
+  task_environment().FastForwardBy(base::TimeDelta::FromSeconds(50));
+  client2->SetViewVisible(true);
+  client2->SetViewAttached(true);
+  client2->SetWindowVisible(true);
+
+  task_environment().FastForwardBy(base::TimeDelta::FromSeconds(50));
+  client2.reset();
+
+  task_environment().FastForwardBy(base::TimeDelta::FromSeconds(50));
+  client1.reset();
+
+  logger()->RecordMetrics();
+  histogram_tester.ExpectBucketCount(
+      "Android.WebView.Visibility.Global",
+      VisibilityMetricsLogger::Visibility::kVisible, 150);
+  histogram_tester.ExpectBucketCount(
+      "Android.WebView.Visibility.Global",
+      VisibilityMetricsLogger::Visibility::kNotVisible, 300);
+  histogram_tester.ExpectBucketCount(
+      "Android.WebView.Visibility.PerWebView",
+      VisibilityMetricsLogger::Visibility::kVisible, 200);
+  histogram_tester.ExpectBucketCount(
+      "Android.WebView.Visibility.PerWebView",
+      VisibilityMetricsLogger::Visibility::kNotVisible, 650);
+}
+
+TEST_F(VisibilityMetricsLoggerTest, TestTwoVisibleClients) {
+  // t=0: client1 created
+  // t=10: client2 created
+  // t=40: client1 visible, recording scheduled for t+60s
+  // t=50: client2 visible
+  // t=60: client1 invisible
+  // t=70: client2 invisible
+  // t=100: clients deleted.
+
+  // Time with any client visible: 70 - 40 = 30
+  // Time with no visible client: 100 - 30 = 70
+  // Time x visible clients: (50-40) * 1 + (60-50) * 2 + (70-60) * 1 = 40
+  // Time x hidden clients: 100 + 90 - 40 = 150
+  base::HistogramTester histogram_tester;
+  std::unique_ptr<TestClient> client1 = std::make_unique<TestClient>(logger());
+
+  task_environment().FastForwardBy(base::TimeDelta::FromSeconds(10));
+  std::unique_ptr<TestClient> client2 = std::make_unique<TestClient>(logger());
+
+  task_environment().FastForwardBy(base::TimeDelta::FromSeconds(30));
+  // This queues delayed recording after 60 seconds (test-defined)
+  client1->SetViewVisible(true);
+  client1->SetViewAttached(true);
+  client1->SetWindowVisible(true);
+
+  task_environment().FastForwardBy(base::TimeDelta::FromSeconds(10));
+  // No additional task is queued
+  client2->SetViewVisible(true);
+  client2->SetViewAttached(true);
+  client2->SetWindowVisible(true);
+
+  task_environment().FastForwardBy(base::TimeDelta::FromSeconds(10));
+  // This does not cause metrics to be recorded because one client remains
+  // visible.
+  client1->SetWindowVisible(false);
+
+  task_environment().FastForwardBy(base::TimeDelta::FromSeconds(10));
+  // The last client becoming invisible triggers immediate recording and the
+  // cancellation of the queued task.
+  client2->SetWindowVisible(false);
+
+  task_environment().FastForwardBy(base::TimeDelta::FromSeconds(30));
+  client1.reset();
+  client2.reset();
+
+  logger()->RecordMetrics();
+  histogram_tester.ExpectBucketCount(
+      "Android.WebView.Visibility.Global",
+      VisibilityMetricsLogger::Visibility::kVisible, 30);
+  histogram_tester.ExpectBucketCount(
+      "Android.WebView.Visibility.Global",
+      VisibilityMetricsLogger::Visibility::kNotVisible, 70);
+  histogram_tester.ExpectBucketCount(
+      "Android.WebView.Visibility.PerWebView",
+      VisibilityMetricsLogger::Visibility::kVisible, 40);
+  histogram_tester.ExpectBucketCount(
+      "Android.WebView.Visibility.PerWebView",
+      VisibilityMetricsLogger::Visibility::kNotVisible, 150);
+}
+
+}  // namespace android_webview
diff --git a/android_webview/browser/metrics/visibility_metrics_provider.cc b/android_webview/browser/metrics/visibility_metrics_provider.cc
new file mode 100644
index 0000000..76ac321
--- /dev/null
+++ b/android_webview/browser/metrics/visibility_metrics_provider.cc
@@ -0,0 +1,22 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "android_webview/browser/metrics/visibility_metrics_provider.h"
+
+#include "android_webview/browser/metrics/visibility_metrics_logger.h"
+
+namespace android_webview {
+
+VisibilityMetricsProvider::VisibilityMetricsProvider(
+    VisibilityMetricsLogger* logger)
+    : logger_(logger) {}
+
+VisibilityMetricsProvider::~VisibilityMetricsProvider() = default;
+
+void VisibilityMetricsProvider::ProvideCurrentSessionData(
+    metrics::ChromeUserMetricsExtension* uma_proto) {
+  logger_->RecordMetrics();
+}
+
+}  // namespace android_webview
\ No newline at end of file
diff --git a/android_webview/browser/metrics/visibility_metrics_provider.h b/android_webview/browser/metrics/visibility_metrics_provider.h
new file mode 100644
index 0000000..37d5f8e
--- /dev/null
+++ b/android_webview/browser/metrics/visibility_metrics_provider.h
@@ -0,0 +1,32 @@
+// 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 ANDROID_WEBVIEW_BROWSER_METRICS_VISIBILITY_METRICS_PROVIDER_H_
+#define ANDROID_WEBVIEW_BROWSER_METRICS_VISIBILITY_METRICS_PROVIDER_H_
+
+#include "components/metrics/metrics_provider.h"
+
+namespace android_webview {
+
+class VisibilityMetricsLogger;
+
+class VisibilityMetricsProvider : public metrics::MetricsProvider {
+ public:
+  explicit VisibilityMetricsProvider(VisibilityMetricsLogger* logger);
+  ~VisibilityMetricsProvider() override;
+
+  VisibilityMetricsProvider() = delete;
+  VisibilityMetricsProvider(const VisibilityMetricsProvider&) = delete;
+
+  // metrics::MetricsProvider
+  void ProvideCurrentSessionData(
+      metrics::ChromeUserMetricsExtension* uma_proto) override;
+
+ private:
+  VisibilityMetricsLogger* logger_;
+};
+
+}  // namespace android_webview
+
+#endif  // ANDROID_WEBVIEW_BROWSER_METRICS_VISIBILITY_METRICS_PROVIDER_H_
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index 253b16d..79b9816 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -426,6 +426,7 @@
     "../browser/input_stream_unittest.cc",
     "../browser/lifecycle/aw_contents_lifecycle_notifier_unittest.cc",
     "../browser/metrics/aw_stability_metrics_provider_unittest.cc",
+    "../browser/metrics/visibility_metrics_logger_unittest.cc",
     "../browser/network_service/android_stream_reader_url_loader_unittest.cc",
     "../browser/network_service/input_stream_reader_unittest.cc",
     "../browser/permission/media_access_permission_request_unittest.cc",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index f6764b6..c57a017 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -2397,6 +2397,22 @@
       <message name="IDS_ASSISTANT_AMBIENT_GREETING_MESSAGE" desc="Greetings message shown on Ambient Mode UI.">
         Hi, <ph name="USERNAME">$1</ph>
       </message>
+      <message name="IDS_ASSISTANT_BETTER_ONBOARDING_GREETING_MORNING" desc="Message shown to greet the user in Assistant UI during the morning.">
+        Good morning <ph name="GIVEN_NAME">$1<ex>David</ex>,</ph>
+      </message>
+      <message name="IDS_ASSISTANT_BETTER_ONBOARDING_GREETING_AFTERNOON" desc="Message shown to greet the user in Assistant UI during the afternoon.">
+        Good afternoon <ph name="GIVEN_NAME">$1<ex>David</ex>,</ph>
+      </message>
+      <message name="IDS_ASSISTANT_BETTER_ONBOARDING_GREETING_EVENING" desc="Message shown to greet the user in Assistant UI during the evening.">
+        Good evening <ph name="GIVEN_NAME">$1<ex>David</ex>,</ph>
+      </message>
+      <message name="IDS_ASSISTANT_BETTER_ONBOARDING_GREETING_NIGHT" desc="Message shown to greet the user in Assistant UI during the night.">
+        Good night <ph name="GIVEN_NAME">$1<ex>David</ex>,</ph>
+      </message>
+      <message name="IDS_ASSISTANT_BETTER_ONBOARDING_INTRO" desc="Message shown to introduce Assistant capabilities to the user.">
+        I'm your Google Assistant, here to help you throughout your day!
+Here are some things you can try to get started.
+      </message>
 
       <message name="IDS_ASH_MESSAGE_CENTER_UNLOCK_TO_PERFORM_ACTION" desc="The short message to encourage user to unlock the device so that Chrome OS can perform the notification action selected by user after unlocking.">
         Unlock device to perform the notification action
diff --git a/ash/assistant/assistant_alarm_timer_controller_impl.cc b/ash/assistant/assistant_alarm_timer_controller_impl.cc
index 418a13c3..9eca4d3 100644
--- a/ash/assistant/assistant_alarm_timer_controller_impl.cc
+++ b/ash/assistant/assistant_alarm_timer_controller_impl.cc
@@ -36,6 +36,7 @@
 using chromeos::assistant::mojom::AssistantNotification;
 using chromeos::assistant::mojom::AssistantNotificationButton;
 using chromeos::assistant::mojom::AssistantNotificationButtonPtr;
+using chromeos::assistant::mojom::AssistantNotificationPriority;
 using chromeos::assistant::mojom::AssistantNotificationPtr;
 
 // Grouping key and ID prefix for timer notifications.
@@ -238,6 +239,32 @@
   return buttons;
 }
 
+// Creates a timer notification priority for the given |timer|.
+AssistantNotificationPriority CreateTimerNotificationPriority(
+    const AssistantTimer& timer) {
+  // In timers v1, all notifications are |kHigh| priority.
+  if (!IsTimersV2Enabled())
+    return AssistantNotificationPriority::kHigh;
+
+  // In timers v2, a notification for a |kFired| timer is |kHigh| priority.
+  // This will cause the notification to pop up to the user.
+  if (timer.state == AssistantTimerState::kFired)
+    return AssistantNotificationPriority::kHigh;
+
+  // If the notification has lived for at least |kPopupThreshold|, drop the
+  // priority to |kLow| so that the notification will not pop up to the user.
+  constexpr base::TimeDelta kPopupThreshold = base::TimeDelta::FromSeconds(6);
+  const base::TimeDelta lifetime =
+      base::Time::Now() - timer.creation_time.value_or(base::Time::Now());
+  if (lifetime >= kPopupThreshold)
+    return AssistantNotificationPriority::kLow;
+
+  // Otherwise, the notification is |kDefault| priority. This means that it
+  // may or may not pop up to the user, depending on the presence of other
+  // notifications.
+  return AssistantNotificationPriority::kDefault;
+}
+
 // Creates a notification for the given |timer|.
 AssistantNotificationPtr CreateTimerNotification(const AssistantTimer& timer) {
   AssistantNotificationPtr notification = AssistantNotification::New();
@@ -247,10 +274,7 @@
   notification->buttons = CreateTimerNotificationButtons(timer);
   notification->client_id = CreateTimerNotificationId(timer);
   notification->grouping_key = kTimerNotificationGroupingKey;
-
-  // This notification should be able to wake up the display if it was off.
-  notification->is_high_priority = true;
-
+  notification->priority = CreateTimerNotificationPriority(timer);
   return notification;
 }
 
@@ -274,6 +298,28 @@
   assistant_ = assistant;
 }
 
+const AssistantAlarmTimerModel* AssistantAlarmTimerControllerImpl::GetModel()
+    const {
+  return &model_;
+}
+
+void AssistantAlarmTimerControllerImpl::OnTimerStateChanged(
+    std::vector<AssistantTimerPtr> new_or_updated_timers) {
+  // First we remove all old timers that no longer exist.
+  for (const auto* old_timer : model_.GetAllTimers()) {
+    if (std::none_of(new_or_updated_timers.begin(), new_or_updated_timers.end(),
+                     [&old_timer](const auto& new_or_updated_timer) {
+                       return old_timer->id == new_or_updated_timer->id;
+                     })) {
+      model_.RemoveTimer(old_timer->id);
+    }
+  }
+
+  // Then we add any new timers and update existing ones.
+  for (auto& new_or_updated_timer : new_or_updated_timers)
+    model_.AddOrUpdateTimer(std::move(new_or_updated_timer));
+}
+
 void AssistantAlarmTimerControllerImpl::OnAssistantControllerConstructed() {
   AssistantState::Get()->AddObserver(this);
 }
@@ -317,28 +363,6 @@
     model_.RemoveAllTimers();
 }
 
-void AssistantAlarmTimerControllerImpl::OnTimerStateChanged(
-    std::vector<AssistantTimerPtr> timers) {
-  if (timers.empty()) {
-    model_.RemoveAllTimers();
-    return;
-  }
-
-  // First we remove all old timers that no longer exist.
-  for (const auto* old_timer : model_.GetAllTimers()) {
-    if (std::none_of(timers.begin(), timers.end(),
-                     [&old_timer](const auto& new_or_updated_timer) {
-                       return old_timer->id == new_or_updated_timer->id;
-                     })) {
-      model_.RemoveTimer(old_timer->id);
-    }
-  }
-
-  // Then we add any new timers and update existing ones.
-  for (auto& new_or_updated_timer : timers)
-    model_.AddOrUpdateTimer(std::move(new_or_updated_timer));
-}
-
 void AssistantAlarmTimerControllerImpl::OnTimerAdded(
     const AssistantTimer& timer) {
   // Schedule a repeating timer to tick the tracked timers.
@@ -376,16 +400,6 @@
       CreateTimerNotificationId(timer), /*from_server=*/false);
 }
 
-void AssistantAlarmTimerControllerImpl::OnAllTimersRemoved() {
-  // We can stop our timer from ticking when all timers are removed.
-  ticker_.Stop();
-
-  // Remove any notifications associated w/ timers.
-  assistant_controller_->notification_controller()
-      ->RemoveNotificationByGroupingKey(kTimerNotificationGroupingKey,
-                                        /*from_server=*/false);
-}
-
 void AssistantAlarmTimerControllerImpl::PerformAlarmTimerAction(
     const AlarmTimerAction& action,
     const std::string& alarm_timer_id,
diff --git a/ash/assistant/assistant_alarm_timer_controller_impl.h b/ash/assistant/assistant_alarm_timer_controller_impl.h
index c8c9ae41..6d88a67 100644
--- a/ash/assistant/assistant_alarm_timer_controller_impl.h
+++ b/ash/assistant/assistant_alarm_timer_controller_impl.h
@@ -46,12 +46,13 @@
       AssistantControllerImpl* assistant_controller);
   ~AssistantAlarmTimerControllerImpl() override;
 
-  // Returns the underlying model.
-  const AssistantAlarmTimerModel* model() const { return &model_; }
-
   // Provides a pointer to the |assistant| owned by AssistantController.
   void SetAssistant(chromeos::assistant::mojom::Assistant* assistant);
 
+  // AssistantAlarmTimerController:
+  const AssistantAlarmTimerModel* GetModel() const override;
+  void OnTimerStateChanged(std::vector<AssistantTimerPtr> timers) override;
+
   // AssistantControllerObserver:
   void OnAssistantControllerConstructed() override;
   void OnAssistantControllerDestroying() override;
@@ -63,14 +64,10 @@
   void OnAssistantStatusChanged(
       chromeos::assistant::AssistantStatus status) override;
 
-  // AssistantAlarmTimerController:
-  void OnTimerStateChanged(std::vector<AssistantTimerPtr> timers) override;
-
   // AssistantAlarmTimerModelObserver:
   void OnTimerAdded(const AssistantTimer& timer) override;
   void OnTimerUpdated(const AssistantTimer& timer) override;
   void OnTimerRemoved(const AssistantTimer& timer) override;
-  void OnAllTimersRemoved() override;
 
  private:
   void PerformAlarmTimerAction(const assistant::util::AlarmTimerAction& action,
diff --git a/ash/assistant/assistant_alarm_timer_controller_unittest.cc b/ash/assistant/assistant_alarm_timer_controller_unittest.cc
index 32694fc..dc4f53e 100644
--- a/ash/assistant/assistant_alarm_timer_controller_unittest.cc
+++ b/ash/assistant/assistant_alarm_timer_controller_unittest.cc
@@ -10,6 +10,8 @@
 
 #include "ash/assistant/assistant_controller_impl.h"
 #include "ash/assistant/assistant_notification_controller.h"
+#include "ash/assistant/model/assistant_alarm_timer_model.h"
+#include "ash/assistant/model/assistant_alarm_timer_model_observer.h"
 #include "ash/assistant/model/assistant_notification_model.h"
 #include "ash/assistant/model/assistant_notification_model_observer.h"
 #include "ash/assistant/util/deep_link_util.h"
@@ -23,6 +25,8 @@
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
 #include "chromeos/services/assistant/public/cpp/features.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace ash {
@@ -32,10 +36,54 @@
 using chromeos::assistant::mojom::AssistantNotification;
 using chromeos::assistant::mojom::AssistantNotificationButton;
 using chromeos::assistant::mojom::AssistantNotificationButtonPtr;
+using chromeos::assistant::mojom::AssistantNotificationPriority;
 using chromeos::assistant::mojom::AssistantNotificationPtr;
 
 // Constants.
 constexpr char kTimerId[] = "1";
+constexpr char kClientId[] = "assistant/timer1";
+
+// Macros ----------------------------------------------------------------------
+
+#define EXPECT_NOTIFICATION_EQ(expected_notif_, notif_)                 \
+  {                                                                     \
+    ASSERT_NE(nullptr, notif_);                                         \
+    if (expected_notif_.client_id_.has_value())                         \
+      EXPECT_EQ(expected_notif_.client_id_.value(), notif_->client_id); \
+    if (expected_notif_.message_.has_value())                           \
+      EXPECT_EQ(expected_notif_.message_.value(), notif_->message);     \
+    if (expected_notif_.priority_.has_value())                          \
+      EXPECT_EQ(expected_notif_.priority_.value(), notif_->priority);   \
+    if (expected_notif_.remove_on_click_.has_value()) {                 \
+      EXPECT_EQ(expected_notif_.remove_on_click_.value(),               \
+                notif_->remove_on_click);                               \
+    }                                                                   \
+    if (expected_notif_.title_.has_value())                             \
+      EXPECT_EQ(expected_notif_.title_.value(), notif_->title);         \
+  }
+
+#define EXPECT_BUTTON_EQ(expected_btn_, btn_)                         \
+  {                                                                   \
+    ASSERT_NE(nullptr, btn_.get());                                   \
+    if (expected_btn_.action_url_.has_value())                        \
+      EXPECT_EQ(expected_btn_.action_url_.value(), btn_->action_url); \
+    if (expected_btn_.label_.has_value())                             \
+      EXPECT_EQ(expected_btn_.label_.value(), btn_->label);           \
+    if (expected_btn_.remove_notification_on_click_.has_value()) {    \
+      EXPECT_EQ(expected_btn_.remove_notification_on_click_.value(),  \
+                btn_->remove_notification_on_click);                  \
+    }                                                                 \
+  }
+
+// Mocks -----------------------------------------------------------------------
+
+class MockAssistantAlarmTimerModelObserver
+    : public testing::NiceMock<AssistantAlarmTimerModelObserver> {
+ public:
+  MOCK_METHOD(void, OnTimerAdded, (const AssistantTimer&), (override));
+
+  MOCK_METHOD(void, OnTimerUpdated, (const AssistantTimer&), (override));
+};
 
 // Test Structs ----------------------------------------------------------------
 
@@ -62,6 +110,11 @@
     return *this;
   }
 
+  TimerEvent& WithCreationTime(base::Optional<base::Time> creation_time) {
+    timer_->creation_time = creation_time;
+    return *this;
+  }
+
   TimerEvent& WithOriginalDuration(base::TimeDelta original_duration) {
     timer_->original_duration = original_duration;
     return *this;
@@ -112,34 +165,75 @@
 
 // Expectations ----------------------------------------------------------------
 
-class ExpectButton {
+class ExpectedNotification {
  public:
-  explicit ExpectButton(const AssistantNotificationButtonPtr& button)
-      : button_(button.get()) {}
+  ExpectedNotification() = default;
+  ExpectedNotification(const ExpectedNotification&) = delete;
+  ExpectedNotification& operator=(const ExpectedNotification&) = delete;
+  ~ExpectedNotification() = default;
 
-  ExpectButton(const ExpectButton&) = delete;
-  ExpectButton& operator=(const ExpectButton&) = delete;
-  ~ExpectButton() = default;
-
-  const ExpectButton& HasLabel(int message_id) const {
-    EXPECT_EQ(l10n_util::GetStringUTF8(message_id), button_->label);
+  ExpectedNotification& WithClientId(const std::string& client_id) {
+    client_id_ = client_id;
     return *this;
   }
 
-  const ExpectButton& HasActionUrl(const GURL& url) const {
-    EXPECT_EQ(url, button_->action_url);
+  ExpectedNotification& WithMessage(const std::string& message) {
+    message_ = message;
     return *this;
   }
 
-  const ExpectButton& HasRemoveNotificationOnClick(
-      bool remove_notification_on_click) const {
-    EXPECT_EQ(remove_notification_on_click,
-              button_->remove_notification_on_click);
+  ExpectedNotification& WithPriority(AssistantNotificationPriority priority) {
+    priority_ = priority;
     return *this;
   }
 
- private:
-  const AssistantNotificationButton* button_;
+  ExpectedNotification& WithRemoveOnClick(bool remove_on_click) {
+    remove_on_click_ = remove_on_click;
+    return *this;
+  }
+
+  ExpectedNotification& WithTitle(const std::string& title) {
+    title_ = title;
+    return *this;
+  }
+
+  ExpectedNotification& WithTitleId(int title_id) {
+    return WithTitle(l10n_util::GetStringUTF8(title_id));
+  }
+
+  base::Optional<std::string> client_id_;
+  base::Optional<std::string> message_;
+  base::Optional<AssistantNotificationPriority> priority_;
+  base::Optional<bool> remove_on_click_;
+  base::Optional<std::string> title_;
+};
+
+class ExpectedButton {
+ public:
+  ExpectedButton() = default;
+  ExpectedButton(const ExpectedButton&) = delete;
+  ExpectedButton& operator=(const ExpectedButton&) = delete;
+  ~ExpectedButton() = default;
+
+  ExpectedButton& WithActionUrl(const GURL& action_url) {
+    action_url_ = action_url;
+    return *this;
+  }
+
+  ExpectedButton& WithLabel(int message_id) {
+    label_ = l10n_util::GetStringUTF8(message_id);
+    return *this;
+  }
+
+  ExpectedButton& WithRemoveNotificationOnClick(
+      bool remove_notification_on_click) {
+    remove_notification_on_click_ = remove_notification_on_click;
+    return *this;
+  }
+
+  base::Optional<GURL> action_url_;
+  base::Optional<std::string> label_;
+  base::Optional<bool> remove_notification_on_click_;
 };
 
 // ScopedNotificationModelObserver ---------------------------------------------
@@ -221,6 +315,80 @@
   DISALLOW_COPY_AND_ASSIGN(AssistantAlarmTimerControllerTest);
 };
 
+// Tests -----------------------------------------------------------------------
+
+// Tests that creation time is properly respected/defaulted when adding a timer.
+TEST_F(AssistantAlarmTimerControllerTest, AddedTimersShouldHaveCreationTime) {
+  MockAssistantAlarmTimerModelObserver mock;
+  controller()->GetModel()->AddObserver(&mock);
+
+  // If unspecified, |creation_time| is expected to be now.
+  base::Time creation_time = base::Time::Now();
+  EXPECT_CALL(mock, OnTimerAdded)
+      .WillOnce(testing::Invoke([&](const AssistantTimer& timer) {
+        EXPECT_EQ(creation_time, timer.creation_time.value());
+      }));
+
+  // Schedule a timer w/o specifying |creation_time|.
+  ScheduleTimer{kTimerId};
+
+  // Reset for the next test case.
+  controller()->OnTimerStateChanged({});
+  testing::Mock::VerifyAndClearExpectations(&mock);
+
+  // If specified, |creation_time| should be respected.
+  creation_time -= base::TimeDelta::FromMinutes(1);
+  EXPECT_CALL(mock, OnTimerAdded)
+      .WillOnce(testing::Invoke([&](const AssistantTimer& timer) {
+        EXPECT_EQ(creation_time, timer.creation_time.value());
+      }));
+
+  // Schedule a timer w/ specified |creation _time|.
+  ScheduleTimer(kTimerId).WithCreationTime(creation_time);
+
+  controller()->GetModel()->RemoveObserver(&mock);
+}
+
+// Tests that creation time is properly respected/carried forward when updating
+// a timer.
+TEST_F(AssistantAlarmTimerControllerTest, UpdatedTimersShouldHaveCreationTime) {
+  MockAssistantAlarmTimerModelObserver mock;
+  controller()->GetModel()->AddObserver(&mock);
+
+  base::Time creation_time = base::Time::Now();
+
+  // Schedule a timer w/ specified |creation_time|.
+  ScheduleTimer(kTimerId).WithCreationTime(creation_time);
+
+  // Advance clock.
+  AdvanceClock(base::TimeDelta::FromMinutes(1));
+
+  // If unspecified, |creation_time| should carry forward on update.
+  EXPECT_CALL(mock, OnTimerUpdated)
+      .WillOnce(testing::Invoke([&](const AssistantTimer& timer) {
+        EXPECT_NE(creation_time, base::Time::Now());
+        EXPECT_EQ(creation_time, timer.creation_time.value());
+      }));
+
+  // Update timer w/o specifying |creation_time|.
+  ScheduleTimer{kTimerId};
+
+  // Reset for the next test case.
+  testing::Mock::VerifyAndClearExpectations(&mock);
+
+  // If specified, |creation_time| should be respected.
+  creation_time += base::TimeDelta::FromHours(1);
+  EXPECT_CALL(mock, OnTimerUpdated)
+      .WillOnce(testing::Invoke([&](const AssistantTimer& timer) {
+        EXPECT_EQ(creation_time, timer.creation_time.value());
+      }));
+
+  // Update timer w/ specified |creation_time|.
+  ScheduleTimer(kTimerId).WithCreationTime(creation_time);
+
+  controller()->GetModel()->RemoveObserver(&mock);
+}
+
 // Tests that a notification is added for a timer and has the expected title.
 // NOTE: This test is only applicable to timers v1.
 TEST_F(AssistantAlarmTimerControllerTest, TimerNotificationHasExpectedTitle) {
@@ -230,17 +398,13 @@
   ScopedNotificationModelObserver notification_model_observer;
 
   // Fire a timer.
-  FireTimer(/*id=*/"1");
+  FireTimer{kTimerId};
 
-  // We expect that a notification exists.
-  auto* last_notification = notification_model_observer.last_notification();
-  ASSERT_NE(nullptr, last_notification);
-  EXPECT_EQ("assistant/timer1", last_notification->client_id);
-
-  // We expect our title to be internationalized.
-  const std::string expected_title =
-      l10n_util::GetStringUTF8(IDS_ASSISTANT_TIMER_NOTIFICATION_TITLE);
-  EXPECT_EQ(expected_title, last_notification->title);
+  // We expect that a notification exists w/ an internationalized title.
+  EXPECT_NOTIFICATION_EQ(
+      ExpectedNotification().WithClientId(kClientId).WithTitleId(
+          IDS_ASSISTANT_TIMER_NOTIFICATION_TITLE),
+      notification_model_observer.last_notification());
 }
 
 // Tests that a notification is added for a timer and has the expected title at
@@ -294,10 +458,9 @@
     ScopedNotificationModelObserver notification_model_observer;
 
     // Schedule a timer.
-    ScheduleTimer(/*id=*/"1")
-        .WithRemainingTime(base::TimeDelta::FromHours(1) +
-                           base::TimeDelta::FromMinutes(1) +
-                           base::TimeDelta::FromSeconds(1));
+    ScheduleTimer(kTimerId).WithRemainingTime(base::TimeDelta::FromHours(1) +
+                                              base::TimeDelta::FromMinutes(1) +
+                                              base::TimeDelta::FromSeconds(1));
 
     // Run each tick of the clock in the test.
     for (auto& tick : i18n_test_case.ticks) {
@@ -305,9 +468,10 @@
       AdvanceClock(tick.advance_clock);
 
       // Make assertions about the notification.
-      auto* last_notification = notification_model_observer.last_notification();
-      EXPECT_EQ("assistant/timer1", last_notification->client_id);
-      EXPECT_EQ(tick.expected_string, last_notification->title);
+      EXPECT_NOTIFICATION_EQ(
+          ExpectedNotification().WithClientId(kClientId).WithTitle(
+              tick.expected_string),
+          notification_model_observer.last_notification());
     }
   }
 }
@@ -353,7 +517,7 @@
     ScopedNotificationModelObserver notification_model_observer;
 
     // Fire a timer.
-    FireTimer(/*id=*/"1");
+    FireTimer{kTimerId};
 
     // Run each tick of the clock in the test.
     for (auto& tick : i18n_test_case.ticks) {
@@ -361,9 +525,10 @@
       AdvanceClock(tick.advance_clock);
 
       // Make assertions about the notification.
-      auto* last_notification = notification_model_observer.last_notification();
-      EXPECT_EQ("assistant/timer1", last_notification->client_id);
-      EXPECT_EQ(tick.expected_string, last_notification->message);
+      EXPECT_NOTIFICATION_EQ(
+          ExpectedNotification().WithClientId(kClientId).WithMessage(
+              tick.expected_string),
+          notification_model_observer.last_notification());
     }
   }
 }
@@ -423,15 +588,15 @@
     // Run each timer in the test.
     for (auto& timer : i18n_test_case.timers) {
       // Schedule a timer.
-      ScheduleTimer(/*id=*/"1")
+      ScheduleTimer(kTimerId)
           .WithLabel(timer.label)
           .WithOriginalDuration(timer.original_duration);
 
       // Make assertions about the notification.
-      auto* last_notification = notification_model_observer.last_notification();
-      ASSERT_NE(nullptr, last_notification);
-      EXPECT_EQ("assistant/timer1", last_notification->client_id);
-      EXPECT_EQ(timer.expected_message, last_notification->message);
+      EXPECT_NOTIFICATION_EQ(
+          ExpectedNotification().WithClientId(kClientId).WithMessage(
+              timer.expected_message),
+          notification_model_observer.last_notification());
     }
   }
 }
@@ -446,29 +611,34 @@
   ScopedNotificationModelObserver notification_model_observer;
 
   // Fire a timer.
-  FireTimer(std::string(kTimerId));
+  FireTimer{kTimerId};
 
   // We expect the timer notification to have two buttons.
   auto* last_notification = notification_model_observer.last_notification();
   ASSERT_EQ(2u, last_notification->buttons.size());
 
   // We expect a "STOP" button which will remove the timer.
-  ExpectButton(last_notification->buttons.at(0))
-      .HasLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_STOP_BUTTON)
-      .HasActionUrl(
-          assistant::util::CreateAlarmTimerDeepLink(
-              assistant::util::AlarmTimerAction::kRemoveAlarmOrTimer, kTimerId)
-              .value())
-      .HasRemoveNotificationOnClick(true);
+  EXPECT_BUTTON_EQ(
+      ExpectedButton()
+          .WithLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_STOP_BUTTON)
+          .WithActionUrl(
+              assistant::util::CreateAlarmTimerDeepLink(
+                  assistant::util::AlarmTimerAction::kRemoveAlarmOrTimer,
+                  kTimerId)
+                  .value())
+          .WithRemoveNotificationOnClick(true),
+      last_notification->buttons.at(0));
 
   // We expect an "ADD 1 MIN" button which will add time to the timer.
-  ExpectButton(last_notification->buttons.at(1))
-      .HasLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_ADD_1_MIN_BUTTON)
-      .HasActionUrl(assistant::util::CreateAlarmTimerDeepLink(
-                        assistant::util::AlarmTimerAction::kAddTimeToTimer,
-                        kTimerId, base::TimeDelta::FromMinutes(1))
-                        .value())
-      .HasRemoveNotificationOnClick(true);
+  EXPECT_BUTTON_EQ(
+      ExpectedButton()
+          .WithLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_ADD_1_MIN_BUTTON)
+          .WithActionUrl(assistant::util::CreateAlarmTimerDeepLink(
+                             assistant::util::AlarmTimerAction::kAddTimeToTimer,
+                             kTimerId, base::TimeDelta::FromMinutes(1))
+                             .value())
+          .WithRemoveNotificationOnClick(true),
+      last_notification->buttons.at(1));
 }
 
 // Tests that a notification is added for a timer and has the expected buttons
@@ -495,22 +665,27 @@
   ASSERT_EQ(2u, last_notification->buttons.size());
 
   // We expect a "PAUSE" button which will pause the timer.
-  ExpectButton(last_notification->buttons.at(0))
-      .HasLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_PAUSE_BUTTON)
-      .HasActionUrl(
-          assistant::util::CreateAlarmTimerDeepLink(
-              assistant::util::AlarmTimerAction::kPauseTimer, kTimerId)
-              .value())
-      .HasRemoveNotificationOnClick(false);
+  EXPECT_BUTTON_EQ(
+      ExpectedButton()
+          .WithLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_PAUSE_BUTTON)
+          .WithActionUrl(
+              assistant::util::CreateAlarmTimerDeepLink(
+                  assistant::util::AlarmTimerAction::kPauseTimer, kTimerId)
+                  .value())
+          .WithRemoveNotificationOnClick(false),
+      last_notification->buttons.at(0));
 
   // We expect a "CANCEL" button which will remove the timer.
-  ExpectButton(last_notification->buttons.at(1))
-      .HasLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_CANCEL_BUTTON)
-      .HasActionUrl(
-          assistant::util::CreateAlarmTimerDeepLink(
-              assistant::util::AlarmTimerAction::kRemoveAlarmOrTimer, kTimerId)
-              .value())
-      .HasRemoveNotificationOnClick(true);
+  EXPECT_BUTTON_EQ(
+      ExpectedButton()
+          .WithLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_CANCEL_BUTTON)
+          .WithActionUrl(
+              assistant::util::CreateAlarmTimerDeepLink(
+                  assistant::util::AlarmTimerAction::kRemoveAlarmOrTimer,
+                  kTimerId)
+                  .value())
+          .WithRemoveNotificationOnClick(true),
+      last_notification->buttons.at(1));
 
   // Pause the timer.
   PauseTimer(kTimerId).WithRemainingTime(kTimeRemaining);
@@ -520,47 +695,57 @@
   ASSERT_EQ(2u, last_notification->buttons.size());
 
   // We expect a "RESUME" button which will resume the timer.
-  ExpectButton(last_notification->buttons.at(0))
-      .HasLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_RESUME_BUTTON)
-      .HasActionUrl(
-          assistant::util::CreateAlarmTimerDeepLink(
-              assistant::util::AlarmTimerAction::kResumeTimer, kTimerId)
-              .value())
-      .HasRemoveNotificationOnClick(false);
+  EXPECT_BUTTON_EQ(
+      ExpectedButton()
+          .WithLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_RESUME_BUTTON)
+          .WithActionUrl(
+              assistant::util::CreateAlarmTimerDeepLink(
+                  assistant::util::AlarmTimerAction::kResumeTimer, kTimerId)
+                  .value())
+          .WithRemoveNotificationOnClick(false),
+      last_notification->buttons.at(0));
 
   // We expect a "CANCEL" button which will remove the timer.
-  ExpectButton(last_notification->buttons.at(1))
-      .HasLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_CANCEL_BUTTON)
-      .HasActionUrl(
-          assistant::util::CreateAlarmTimerDeepLink(
-              assistant::util::AlarmTimerAction::kRemoveAlarmOrTimer, kTimerId)
-              .value())
-      .HasRemoveNotificationOnClick(true);
+  EXPECT_BUTTON_EQ(
+      ExpectedButton()
+          .WithLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_CANCEL_BUTTON)
+          .WithActionUrl(
+              assistant::util::CreateAlarmTimerDeepLink(
+                  assistant::util::AlarmTimerAction::kRemoveAlarmOrTimer,
+                  kTimerId)
+                  .value())
+          .WithRemoveNotificationOnClick(true),
+      last_notification->buttons.at(1));
 
   // Fire the timer.
-  FireTimer(std::string(kTimerId));
+  FireTimer{kTimerId};
 
   // We expect the timer notification to have two buttons.
   last_notification = notification_model_observer.last_notification();
   ASSERT_EQ(2u, last_notification->buttons.size());
 
   // We expect a "CANCEL" button which will remove the timer.
-  ExpectButton(last_notification->buttons.at(0))
-      .HasLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_CANCEL_BUTTON)
-      .HasActionUrl(
-          assistant::util::CreateAlarmTimerDeepLink(
-              assistant::util::AlarmTimerAction::kRemoveAlarmOrTimer, kTimerId)
-              .value())
-      .HasRemoveNotificationOnClick(true);
+  EXPECT_BUTTON_EQ(
+      ExpectedButton()
+          .WithLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_CANCEL_BUTTON)
+          .WithActionUrl(
+              assistant::util::CreateAlarmTimerDeepLink(
+                  assistant::util::AlarmTimerAction::kRemoveAlarmOrTimer,
+                  kTimerId)
+                  .value())
+          .WithRemoveNotificationOnClick(true),
+      last_notification->buttons.at(0));
 
   // We expect an "ADD 1 MIN" button which will add time to the timer.
-  ExpectButton(last_notification->buttons.at(1))
-      .HasLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_ADD_1_MIN_BUTTON)
-      .HasActionUrl(assistant::util::CreateAlarmTimerDeepLink(
-                        assistant::util::AlarmTimerAction::kAddTimeToTimer,
-                        kTimerId, base::TimeDelta::FromMinutes(1))
-                        .value())
-      .HasRemoveNotificationOnClick(false);
+  EXPECT_BUTTON_EQ(
+      ExpectedButton()
+          .WithLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_ADD_1_MIN_BUTTON)
+          .WithActionUrl(assistant::util::CreateAlarmTimerDeepLink(
+                             assistant::util::AlarmTimerAction::kAddTimeToTimer,
+                             kTimerId, base::TimeDelta::FromMinutes(1))
+                             .value())
+          .WithRemoveNotificationOnClick(false),
+      last_notification->buttons.at(1));
 }
 
 // Tests that a notification is added for a timer and has the expected value to
@@ -571,13 +756,74 @@
   ScopedNotificationModelObserver notification_model_observer;
 
   // Fire a timer.
-  FireTimer(std::string(kTimerId));
+  FireTimer{kTimerId};
 
   // Make assertions about the notification.
-  auto* last_notification = notification_model_observer.last_notification();
-  ASSERT_NE(nullptr, last_notification);
-  EXPECT_EQ("assistant/timer1", last_notification->client_id);
-  EXPECT_EQ(true, last_notification->remove_on_click);
+  EXPECT_NOTIFICATION_EQ(
+      ExpectedNotification().WithClientId(kClientId).WithRemoveOnClick(true),
+      notification_model_observer.last_notification());
+}
+
+// Tests that a notification is added for a timer and has the expected priority.
+// NOTE: This test is only applicable to timers v1.
+TEST_F(AssistantAlarmTimerControllerTest,
+       TimerNotificationHasExpectedPriority) {
+  ASSERT_FALSE(chromeos::assistant::features::IsTimersV2Enabled());
+
+  // Observe notifications.
+  ScopedNotificationModelObserver notification_model_observer;
+
+  // Fire a timer.
+  FireTimer{kTimerId};
+
+  // Make assertions about the notification.
+  EXPECT_NOTIFICATION_EQ(
+      ExpectedNotification().WithClientId(kClientId).WithPriority(
+          AssistantNotificationPriority::kHigh),
+      notification_model_observer.last_notification());
+}
+
+// Tests that a notification is added for a timer and has the expected priority
+// at various stages of its lifecycle.
+// NOTE: This test is only applicable to timers v2.
+TEST_F(AssistantAlarmTimerControllerTest,
+       TimerNotificationHasExpectedPriorityV2) {
+  // Enable timers v2.
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      chromeos::assistant::features::kAssistantTimersV2);
+  ASSERT_TRUE(chromeos::assistant::features::IsTimersV2Enabled());
+
+  // Observe notifications.
+  ScopedNotificationModelObserver notification_model_observer;
+
+  // Schedule a timer.
+  ScheduleTimer{kTimerId};
+
+  // Make assertions about the notification.
+  EXPECT_NOTIFICATION_EQ(
+      ExpectedNotification().WithClientId(kClientId).WithPriority(
+          AssistantNotificationPriority::kDefault),
+      notification_model_observer.last_notification());
+
+  // Advance the clock.
+  // NOTE: Six seconds is the threshold for popping up our notification.
+  AdvanceClock(base::TimeDelta::FromSeconds(6));
+
+  // Make assertions about the notification.
+  EXPECT_NOTIFICATION_EQ(
+      ExpectedNotification().WithClientId(kClientId).WithPriority(
+          AssistantNotificationPriority::kLow),
+      notification_model_observer.last_notification());
+
+  // Fire the timer.
+  FireTimer{kTimerId};
+
+  // Make assertions about the notification.
+  EXPECT_NOTIFICATION_EQ(
+      ExpectedNotification().WithClientId(kClientId).WithPriority(
+          AssistantNotificationPriority::kHigh),
+      notification_model_observer.last_notification());
 }
 
 }  // namespace ash
diff --git a/ash/assistant/assistant_notification_controller.cc b/ash/assistant/assistant_notification_controller.cc
index 4e690a7..2ad678b0 100644
--- a/ash/assistant/assistant_notification_controller.cc
+++ b/ash/assistant/assistant_notification_controller.cc
@@ -53,8 +53,17 @@
           /*delegate=*/nullptr, kNotificationAssistantIcon,
           message_center::SystemNotificationWarningLevel::NORMAL);
 
-  if (notification->is_high_priority)
-    system_notification->set_priority(message_center::HIGH_PRIORITY);
+  switch (notification->priority) {
+    case chromeos::assistant::mojom::AssistantNotificationPriority::kLow:
+      system_notification->set_priority(message_center::LOW_PRIORITY);
+      break;
+    case chromeos::assistant::mojom::AssistantNotificationPriority::kDefault:
+      system_notification->set_priority(message_center::DEFAULT_PRIORITY);
+      break;
+    case chromeos::assistant::mojom::AssistantNotificationPriority::kHigh:
+      system_notification->set_priority(message_center::HIGH_PRIORITY);
+      break;
+  }
 
   return system_notification;
 }
diff --git a/ash/assistant/assistant_notification_controller_unittest.cc b/ash/assistant/assistant_notification_controller_unittest.cc
index 5ff77ea6..d5a11bb9 100644
--- a/ash/assistant/assistant_notification_controller_unittest.cc
+++ b/ash/assistant/assistant_notification_controller_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "ash/assistant/assistant_notification_controller.h"
 
+#include <map>
+
 #include "ash/assistant/assistant_controller_impl.h"
 #include "ash/assistant/model/assistant_notification_model_observer.h"
 #include "ash/shell.h"
@@ -22,7 +24,9 @@
 using chromeos::assistant::mojom::AssistantNotification;
 using chromeos::assistant::mojom::AssistantNotificationButton;
 using chromeos::assistant::mojom::AssistantNotificationButtonPtr;
+using chromeos::assistant::mojom::AssistantNotificationPriority;
 using chromeos::assistant::mojom::AssistantNotificationPtr;
+
 using testing::_;
 using testing::Eq;
 using testing::Field;
@@ -81,6 +85,12 @@
     return *this;
   }
 
+  AssistantNotificationBuilder& WithPriority(
+      AssistantNotificationPriority priority) {
+    notification_->priority = priority;
+    return *this;
+  }
+
   AssistantNotificationBuilder& WithRemoveOnClick(bool remove_on_click) {
     notification_->remove_on_click = remove_on_click;
     return *this;
@@ -187,11 +197,7 @@
     return *observer_;
   }
 
-  void AddNotification(AssistantNotificationPtr notification) {
-    controller().AddOrUpdateNotification(std::move(notification));
-  }
-
-  void UpdateNotification(AssistantNotificationPtr notification) {
+  void AddOrUpdateNotification(AssistantNotificationPtr notification) {
     controller().AddOrUpdateNotification(std::move(notification));
   }
 
@@ -265,10 +271,10 @@
        ShouldRemoveNotificationWhenItExpires) {
   constexpr int kTimeoutMs = 1000;
 
-  AddNotification(AssistantNotificationBuilder()
-                      .WithId("id")
-                      .WithTimeoutMs((kTimeoutMs))
-                      .Build());
+  AddOrUpdateNotification(AssistantNotificationBuilder()
+                              .WithId("id")
+                              .WithTimeoutMs((kTimeoutMs))
+                              .Build());
 
   auto& observer = AddStrictObserverMock();
 
@@ -280,10 +286,10 @@
        ShouldNotRemoveNotificationsTooSoon) {
   constexpr int kTimeoutMs = 1000;
 
-  AddNotification(AssistantNotificationBuilder()
-                      .WithId("id")
-                      .WithTimeoutMs(kTimeoutMs)
-                      .Build());
+  AddOrUpdateNotification(AssistantNotificationBuilder()
+                              .WithId("id")
+                              .WithTimeoutMs(kTimeoutMs)
+                              .Build());
 
   auto& observer = AddStrictObserverMock();
 
@@ -295,10 +301,10 @@
        ShouldUseFromServerFalseWhenNotificationExpires) {
   constexpr int kTimeoutMs = 1000;
 
-  AddNotification(AssistantNotificationBuilder()
-                      .WithId("id")
-                      .WithTimeoutMs(kTimeoutMs)
-                      .Build());
+  AddOrUpdateNotification(AssistantNotificationBuilder()
+                              .WithId("id")
+                              .WithTimeoutMs(kTimeoutMs)
+                              .Build());
 
   auto& observer = AddStrictObserverMock();
 
@@ -311,14 +317,14 @@
   constexpr int kFirstTimeoutMs = 1000;
   constexpr int kSecondTimeoutMs = 1500;
 
-  AddNotification(AssistantNotificationBuilder()
-                      .WithId("first")
-                      .WithTimeoutMs(kFirstTimeoutMs)
-                      .Build());
-  AddNotification(AssistantNotificationBuilder()
-                      .WithId("second")
-                      .WithTimeoutMs(kSecondTimeoutMs)
-                      .Build());
+  AddOrUpdateNotification(AssistantNotificationBuilder()
+                              .WithId("first")
+                              .WithTimeoutMs(kFirstTimeoutMs)
+                              .Build());
+  AddOrUpdateNotification(AssistantNotificationBuilder()
+                              .WithId("second")
+                              .WithTimeoutMs(kSecondTimeoutMs)
+                              .Build());
 
   auto& observer = AddStrictObserverMock();
 
@@ -333,14 +339,14 @@
        ShouldSupport2NotificationsThatExpireAtTheSameTime) {
   constexpr int kTimeoutMs = 1000;
 
-  AddNotification(AssistantNotificationBuilder()
-                      .WithId("first")
-                      .WithTimeoutMs(kTimeoutMs)
-                      .Build());
-  AddNotification(AssistantNotificationBuilder()
-                      .WithId("at-same-time")
-                      .WithTimeoutMs(kTimeoutMs)
-                      .Build());
+  AddOrUpdateNotification(AssistantNotificationBuilder()
+                              .WithId("first")
+                              .WithTimeoutMs(kTimeoutMs)
+                              .Build());
+  AddOrUpdateNotification(AssistantNotificationBuilder()
+                              .WithId("at-same-time")
+                              .WithTimeoutMs(kTimeoutMs)
+                              .Build());
 
   auto& observer = AddStrictObserverMock();
 
@@ -353,10 +359,10 @@
        ShouldImmediateRemoveNotificationsThatAlreadyExpired) {
   constexpr int kNegativeTimeoutMs = -1000;
 
-  AddNotification(AssistantNotificationBuilder()
-                      .WithId("expired")
-                      .WithTimeoutMs(kNegativeTimeoutMs)
-                      .Build());
+  AddOrUpdateNotification(AssistantNotificationBuilder()
+                              .WithId("expired")
+                              .WithTimeoutMs(kNegativeTimeoutMs)
+                              .Build());
 
   auto& observer = AddStrictObserverMock();
 
@@ -367,10 +373,10 @@
        ShouldNotRemoveNotificationsThatWereManuallyRemoved) {
   constexpr int kTimeoutMs = 1000;
 
-  AddNotification(AssistantNotificationBuilder()
-                      .WithId("id")
-                      .WithTimeoutMs(kTimeoutMs)
-                      .Build());
+  AddOrUpdateNotification(AssistantNotificationBuilder()
+                              .WithId("id")
+                              .WithTimeoutMs(kTimeoutMs)
+                              .Build());
   RemoveNotification("id");
 
   auto& observer = AddStrictObserverMock();
@@ -385,8 +391,8 @@
 
   auto notification_bldr = AssistantNotificationBuilder().WithId("id");
 
-  AddNotification(notification_bldr.Build());
-  UpdateNotification(notification_bldr.WithTimeoutMs(kTimeoutMs).Build());
+  AddOrUpdateNotification(notification_bldr.Build());
+  AddOrUpdateNotification(notification_bldr.WithTimeoutMs(kTimeoutMs).Build());
 
   auto& observer = AddStrictObserverMock();
 
@@ -400,8 +406,8 @@
 
   auto notification_bldr = AssistantNotificationBuilder().WithId("id");
 
-  AddNotification(notification_bldr.WithTimeoutMs(kTimeoutMs).Build());
-  UpdateNotification(notification_bldr.WithTimeout(base::nullopt).Build());
+  AddOrUpdateNotification(notification_bldr.WithTimeoutMs(kTimeoutMs).Build());
+  AddOrUpdateNotification(notification_bldr.WithTimeout(base::nullopt).Build());
 
   auto& observer = AddStrictObserverMock();
 
@@ -417,7 +423,7 @@
       AssistantNotificationBuilder().WithId(kId).WithActionUrl(
           GURL("https://g.co/"));
 
-  AddNotification(notification_bldr.WithRemoveOnClick(false).Build());
+  AddOrUpdateNotification(notification_bldr.WithRemoveOnClick(false).Build());
 
   auto& observer = AddStrictObserverMock();
 
@@ -429,7 +435,7 @@
   Mock::VerifyAndClearExpectations(&observer);
 
   EXPECT_CALL(observer, OnNotificationUpdated(IdIs(kId)));
-  UpdateNotification(notification_bldr.WithRemoveOnClick(true).Build());
+  AddOrUpdateNotification(notification_bldr.WithRemoveOnClick(true).Build());
 
   EXPECT_CALL(observer, OnNotificationRemoved(IdIs(kId), _));
   message_center->ClickOnNotification(kId);
@@ -443,7 +449,7 @@
   auto button_bldr =
       AssistantNotificationButtonBuilder().WithActionUrl(GURL("https://g.co/"));
 
-  AddNotification(
+  AddOrUpdateNotification(
       notification_bldr
           .WithButton(button_bldr.WithRemoveNotificationOnClick(false).Build())
           .Build());
@@ -458,7 +464,7 @@
   Mock::VerifyAndClearExpectations(&observer);
 
   EXPECT_CALL(observer, OnNotificationUpdated(IdIs(kId)));
-  UpdateNotification(
+  AddOrUpdateNotification(
       notification_bldr
           .WithButton(button_bldr.WithRemoveNotificationOnClick(true).Build(),
                       /*index=*/0)
@@ -468,4 +474,33 @@
   message_center->ClickOnNotificationButton(kId, /*index=*/0);
 }
 
+TEST_F(AssistantNotificationControllerTest,
+       ShouldCorrectlyMapNotificationPriority) {
+  constexpr char kId[] = "id";
+
+  // Map of Assistant notification priorities to system notification priorities.
+  const std::map<AssistantNotificationPriority,
+                 message_center::NotificationPriority>
+      priority_map = {{AssistantNotificationPriority::kLow,
+                       message_center::NotificationPriority::LOW_PRIORITY},
+                      {AssistantNotificationPriority::kDefault,
+                       message_center::NotificationPriority::DEFAULT_PRIORITY},
+                      {AssistantNotificationPriority::kHigh,
+                       message_center::NotificationPriority::HIGH_PRIORITY}};
+
+  for (const auto& priority_pair : priority_map) {
+    // Create an Assistant notification.
+    AddOrUpdateNotification(AssistantNotificationBuilder()
+                                .WithId(kId)
+                                .WithPriority(priority_pair.first)
+                                .Build());
+
+    // Verify expected system notification.
+    auto* system_notification =
+        message_center::MessageCenter::Get()->FindVisibleNotificationById(kId);
+    ASSERT_NE(nullptr, system_notification);
+    EXPECT_EQ(priority_pair.second, system_notification->priority());
+  }
+}
+
 }  // namespace ash
diff --git a/ash/assistant/assistant_view_delegate_impl.cc b/ash/assistant/assistant_view_delegate_impl.cc
index 9fd9c0a4..d0706ed 100644
--- a/ash/assistant/assistant_view_delegate_impl.cc
+++ b/ash/assistant/assistant_view_delegate_impl.cc
@@ -25,11 +25,6 @@
 
 AssistantViewDelegateImpl::~AssistantViewDelegateImpl() = default;
 
-const AssistantAlarmTimerModel* AssistantViewDelegateImpl::GetAlarmTimerModel()
-    const {
-  return assistant_controller_->alarm_timer_controller()->model();
-}
-
 const AssistantNotificationModel*
 AssistantViewDelegateImpl::GetNotificationModel() const {
   return assistant_controller_->notification_controller()->model();
diff --git a/ash/assistant/assistant_view_delegate_impl.h b/ash/assistant/assistant_view_delegate_impl.h
index 7e11a26..97295ba4 100644
--- a/ash/assistant/assistant_view_delegate_impl.h
+++ b/ash/assistant/assistant_view_delegate_impl.h
@@ -20,7 +20,6 @@
   ~AssistantViewDelegateImpl() override;
 
   // AssistantViewDelegate:
-  const AssistantAlarmTimerModel* GetAlarmTimerModel() const override;
   const AssistantNotificationModel* GetNotificationModel() const override;
   void AddObserver(AssistantViewDelegateObserver* observer) override;
   void RemoveObserver(AssistantViewDelegateObserver* observer) override;
diff --git a/ash/assistant/model/assistant_alarm_timer_model.cc b/ash/assistant/model/assistant_alarm_timer_model.cc
index 3c2e63d3..4f97135 100644
--- a/ash/assistant/model/assistant_alarm_timer_model.cc
+++ b/ash/assistant/model/assistant_alarm_timer_model.cc
@@ -31,11 +31,17 @@
 
   auto it = timers_.find(timer->id);
   if (it == timers_.end()) {
+    timer->creation_time = timer->creation_time.value_or(base::Time::Now());
     timers_[ptr->id] = std::move(timer);
     NotifyTimerAdded(*ptr);
     return;
   }
 
+  // If not explicitly provided, carry forward |creation_time|. This allows us
+  // to track the lifetime of |timer| across updates.
+  timer->creation_time =
+      timer->creation_time.value_or(timers_[ptr->id]->creation_time.value());
+
   timers_[ptr->id] = std::move(timer);
   NotifyTimerUpdated(*ptr);
 }
@@ -52,11 +58,8 @@
 }
 
 void AssistantAlarmTimerModel::RemoveAllTimers() {
-  if (timers_.empty())
-    return;
-
-  timers_.clear();
-  NotifyAllTimersRemoved();
+  while (!timers_.empty())
+    RemoveTimer(timers_.begin()->second->id);
 }
 
 std::vector<const AssistantTimer*> AssistantAlarmTimerModel::GetAllTimers()
@@ -102,9 +105,4 @@
     observer.OnTimerRemoved(timer);
 }
 
-void AssistantAlarmTimerModel::NotifyAllTimersRemoved() {
-  for (auto& observer : observers_)
-    observer.OnAllTimersRemoved();
-}
-
 }  // namespace ash
diff --git a/ash/assistant/model/assistant_alarm_timer_model.h b/ash/assistant/model/assistant_alarm_timer_model.h
index 6e8b69a..f18cf578 100644
--- a/ash/assistant/model/assistant_alarm_timer_model.h
+++ b/ash/assistant/model/assistant_alarm_timer_model.h
@@ -55,7 +55,6 @@
   void NotifyTimerAdded(const AssistantTimer& timer);
   void NotifyTimerUpdated(const AssistantTimer& timer);
   void NotifyTimerRemoved(const AssistantTimer& timer);
-  void NotifyAllTimersRemoved();
 
   std::map<std::string, AssistantTimerPtr> timers_;
 
diff --git a/ash/assistant/model/assistant_alarm_timer_model_observer.h b/ash/assistant/model/assistant_alarm_timer_model_observer.h
index ccecb8e..965318f 100644
--- a/ash/assistant/model/assistant_alarm_timer_model_observer.h
+++ b/ash/assistant/model/assistant_alarm_timer_model_observer.h
@@ -28,9 +28,6 @@
   // Invoked when the specified timer has been removed.
   virtual void OnTimerRemoved(const AssistantTimer& timer) {}
 
-  // Invoked when all timers have been removed.
-  virtual void OnAllTimersRemoved() {}
-
  protected:
   ~AssistantAlarmTimerModelObserver() override = default;
 };
diff --git a/ash/assistant/ui/assistant_view_delegate.h b/ash/assistant/ui/assistant_view_delegate.h
index da4ac648..26b77198 100644
--- a/ash/assistant/ui/assistant_view_delegate.h
+++ b/ash/assistant/ui/assistant_view_delegate.h
@@ -17,7 +17,6 @@
 
 namespace ash {
 
-class AssistantAlarmTimerModel;
 class AssistantNotificationModel;
 enum class AssistantButtonId;
 
@@ -57,9 +56,6 @@
 
   virtual ~AssistantViewDelegate() {}
 
-  // Gets the alarm/timer model.
-  virtual const AssistantAlarmTimerModel* GetAlarmTimerModel() const = 0;
-
   // Gets the notification model.
   virtual const AssistantNotificationModel* GetNotificationModel() const = 0;
 
diff --git a/ash/assistant/ui/main_stage/assistant_onboarding_view.cc b/ash/assistant/ui/main_stage/assistant_onboarding_view.cc
index 861ea850..e4d1515 100644
--- a/ash/assistant/ui/main_stage/assistant_onboarding_view.cc
+++ b/ash/assistant/ui/main_stage/assistant_onboarding_view.cc
@@ -5,11 +5,15 @@
 #include "ash/assistant/ui/main_stage/assistant_onboarding_view.h"
 
 #include <memory>
+#include <string>
 
 #include "ash/assistant/ui/assistant_ui_constants.h"
 #include "ash/assistant/ui/assistant_view_delegate.h"
 #include "ash/assistant/ui/assistant_view_ids.h"
+#include "ash/strings/grit/ash_strings.h"
 #include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/label.h"
@@ -17,6 +21,47 @@
 
 namespace ash {
 
+namespace {
+
+// Helpers ---------------------------------------------------------------------
+
+std::string GetGreetingMessage(AssistantViewDelegate* delegate) {
+  base::Time::Exploded now;
+  base::Time::Now().LocalExplode(&now);
+
+  if (now.hour < 5) {
+    return l10n_util::GetStringFUTF8(
+        IDS_ASSISTANT_BETTER_ONBOARDING_GREETING_NIGHT,
+        base::UTF8ToUTF16(delegate->GetPrimaryUserGivenName()));
+  }
+
+  if (now.hour < 12) {
+    return l10n_util::GetStringFUTF8(
+        IDS_ASSISTANT_BETTER_ONBOARDING_GREETING_MORNING,
+        base::UTF8ToUTF16(delegate->GetPrimaryUserGivenName()));
+  }
+
+  if (now.hour < 17) {
+    return l10n_util::GetStringFUTF8(
+        IDS_ASSISTANT_BETTER_ONBOARDING_GREETING_AFTERNOON,
+        base::UTF8ToUTF16(delegate->GetPrimaryUserGivenName()));
+  }
+
+  if (now.hour < 23) {
+    return l10n_util::GetStringFUTF8(
+        IDS_ASSISTANT_BETTER_ONBOARDING_GREETING_EVENING,
+        base::UTF8ToUTF16(delegate->GetPrimaryUserGivenName()));
+  }
+
+  return l10n_util::GetStringFUTF8(
+      IDS_ASSISTANT_BETTER_ONBOARDING_GREETING_NIGHT,
+      base::UTF8ToUTF16(delegate->GetPrimaryUserGivenName()));
+}
+
+}  // namespace
+
+// AssistantOnboardingView -----------------------------------------------------
+
 AssistantOnboardingView::AssistantOnboardingView(
     AssistantViewDelegate* delegate)
     : delegate_(delegate) {
@@ -39,7 +84,6 @@
 }
 
 // TODO(dmblack): Implement suggestions.
-// TODO(dmblack): Finalize strings.
 void AssistantOnboardingView::InitLayout() {
   SetBackground(views::CreateSolidBackground(
       SkColorSetA(gfx::kPlaceholderColor, 0.2 * 0xFF)));
@@ -54,21 +98,19 @@
   greeting->SetBackground(views::CreateSolidBackground(SK_ColorWHITE));
   greeting->SetEnabledColor(kTextColorPrimary);
   greeting->SetFontList(assistant::ui::GetDefaultFontList());
-  greeting->SetText(base::UTF8ToUTF16(base::StringPrintf(
-      "Good morning %s,", delegate_->GetPrimaryUserGivenName().c_str())));
+  greeting->SetText(base::UTF8ToUTF16(GetGreetingMessage(delegate_)));
   AddChildView(std::move(greeting));
 
-  // Description.
-  auto description = std::make_unique<views::Label>();
-  description->SetAutoColorReadabilityEnabled(false);
-  description->SetBackground(views::CreateSolidBackground(SK_ColorWHITE));
-  description->SetEnabledColor(kTextColorPrimary);
-  description->SetFontList(assistant::ui::GetDefaultFontList());
-  description->SetMultiLine(true);
-  description->SetText(base::UTF8ToUTF16(
-      "I'm your Google Assistant, here to help you throughout your day!\nHere "
-      "are some things you can try to get started."));
-  AddChildView(std::move(description));
+  // Intro.
+  auto intro = std::make_unique<views::Label>();
+  intro->SetAutoColorReadabilityEnabled(false);
+  intro->SetBackground(views::CreateSolidBackground(SK_ColorWHITE));
+  intro->SetEnabledColor(kTextColorPrimary);
+  intro->SetFontList(assistant::ui::GetDefaultFontList());
+  intro->SetMultiLine(true);
+  intro->SetText(
+      l10n_util::GetStringUTF16(IDS_ASSISTANT_BETTER_ONBOARDING_INTRO));
+  AddChildView(std::move(intro));
 
   // Suggestions.
   auto* suggestions = AddChildView(std::make_unique<views::View>());
diff --git a/ash/assistant/ui/main_stage/assistant_onboarding_view_unittest.cc b/ash/assistant/ui/main_stage/assistant_onboarding_view_unittest.cc
index ddd989d..08d0782 100644
--- a/ash/assistant/ui/main_stage/assistant_onboarding_view_unittest.cc
+++ b/ash/assistant/ui/main_stage/assistant_onboarding_view_unittest.cc
@@ -7,10 +7,11 @@
 #include <memory>
 #include <string>
 
-#include "ash/assistant/test/assistant_ash_test_base.h"
 #include "ash/assistant/ui/test_support/mock_assistant_view_delegate.h"
+#include "ash/test/ash_test_base.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/icu_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/views/controls/label.h"
 
@@ -25,20 +26,29 @@
 
 // AssistantOnboardingViewTest -------------------------------------------------
 
-class AssistantOnboardingViewTest : public AssistantAshTestBase {
+class AssistantOnboardingViewTest : public AshTestBase {
  public:
-  AssistantOnboardingViewTest() = default;
+  AssistantOnboardingViewTest()
+      : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
   ~AssistantOnboardingViewTest() override = default;
 
-  // AssistantAshTestBase:
+  // AshTestBase:
   void SetUp() override {
-    AssistantAshTestBase::SetUp();
+    AshTestBase::SetUp();
 
     delegate_ = std::make_unique<MockAssistantViewDelegate>();
 
     ON_CALL(*delegate_, GetPrimaryUserGivenName())
         .WillByDefault(Return(kPrimaryUserGivenName));
 
+    RecreateView();
+  }
+
+  void AdvanceClock(base::TimeDelta time_delta) {
+    task_environment()->AdvanceClock(time_delta);
+  }
+
+  void RecreateView() {
     view_ = std::make_unique<AssistantOnboardingView>(delegate_.get());
   }
 
@@ -48,11 +58,12 @@
     return static_cast<views::Label*>(view_->children().at(0));
   }
 
-  views::Label* description_label() {
+  views::Label* intro_label() {
     return static_cast<views::Label*>(view_->children().at(1));
   }
 
  private:
+  base::test::ScopedRestoreICUDefaultLocale locale{"en_US"};
   std::unique_ptr<MockAssistantViewDelegate> delegate_;
   std::unique_ptr<AssistantOnboardingView> view_;
 };
@@ -62,13 +73,77 @@
 // Tests -----------------------------------------------------------------------
 
 TEST_F(AssistantOnboardingViewTest, ShouldHaveExpectedGreeting) {
+  // Advance clock to midnight.
+  base::Time::Exploded now;
+  base::Time::Now().LocalExplode(&now);
+  AdvanceClock(base::TimeDelta::FromHours((24 - now.hour) % 24) -
+               base::TimeDelta::FromMinutes(now.minute) -
+               base::TimeDelta::FromSeconds(now.second) -
+               base::TimeDelta::FromMilliseconds(now.millisecond));
+
+  // Verify 4:59 AM.
+  AdvanceClock(base::TimeDelta::FromHours(4) +
+               base::TimeDelta::FromMinutes(59));
+  RecreateView();
+  EXPECT_EQ(greeting_label()->GetText(),
+            base::UTF8ToUTF16(
+                base::StringPrintf("Good night %s,", kPrimaryUserGivenName)));
+
+  // Verify 5:00 AM.
+  AdvanceClock(base::TimeDelta::FromMinutes(1));
+  RecreateView();
   EXPECT_EQ(greeting_label()->GetText(),
             base::UTF8ToUTF16(
                 base::StringPrintf("Good morning %s,", kPrimaryUserGivenName)));
+
+  // Verify 11:59 AM.
+  AdvanceClock(base::TimeDelta::FromHours(6) +
+               base::TimeDelta::FromMinutes(59));
+  RecreateView();
+  EXPECT_EQ(greeting_label()->GetText(),
+            base::UTF8ToUTF16(
+                base::StringPrintf("Good morning %s,", kPrimaryUserGivenName)));
+
+  // Verify 12:00 PM.
+  AdvanceClock(base::TimeDelta::FromMinutes(1));
+  RecreateView();
+  EXPECT_EQ(greeting_label()->GetText(),
+            base::UTF8ToUTF16(base::StringPrintf("Good afternoon %s,",
+                                                 kPrimaryUserGivenName)));
+
+  // Verify 4:59 PM.
+  AdvanceClock(base::TimeDelta::FromHours(4) +
+               base::TimeDelta::FromMinutes(59));
+  RecreateView();
+  EXPECT_EQ(greeting_label()->GetText(),
+            base::UTF8ToUTF16(base::StringPrintf("Good afternoon %s,",
+                                                 kPrimaryUserGivenName)));
+
+  // Verify 5:00 PM.
+  AdvanceClock(base::TimeDelta::FromMinutes(1));
+  RecreateView();
+  EXPECT_EQ(greeting_label()->GetText(),
+            base::UTF8ToUTF16(
+                base::StringPrintf("Good evening %s,", kPrimaryUserGivenName)));
+
+  // Verify 10:59 PM.
+  AdvanceClock(base::TimeDelta::FromHours(5) +
+               base::TimeDelta::FromMinutes(59));
+  RecreateView();
+  EXPECT_EQ(greeting_label()->GetText(),
+            base::UTF8ToUTF16(
+                base::StringPrintf("Good evening %s,", kPrimaryUserGivenName)));
+
+  // Verify 11:00 PM.
+  AdvanceClock(base::TimeDelta::FromMinutes(1));
+  RecreateView();
+  EXPECT_EQ(greeting_label()->GetText(),
+            base::UTF8ToUTF16(
+                base::StringPrintf("Good night %s,", kPrimaryUserGivenName)));
 }
 
-TEST_F(AssistantOnboardingViewTest, ShouldHaveExpectedDescription) {
-  EXPECT_EQ(description_label()->GetText(),
+TEST_F(AssistantOnboardingViewTest, ShouldHaveExpectedIntro) {
+  EXPECT_EQ(intro_label()->GetText(),
             base::UTF8ToUTF16(
                 "I'm your Google Assistant, here to help you throughout your "
                 "day!\nHere are some things you can try to get started."));
diff --git a/ash/assistant/ui/test_support/mock_assistant_view_delegate.h b/ash/assistant/ui/test_support/mock_assistant_view_delegate.h
index e2920c35..e638cdb 100644
--- a/ash/assistant/ui/test_support/mock_assistant_view_delegate.h
+++ b/ash/assistant/ui/test_support/mock_assistant_view_delegate.h
@@ -27,11 +27,6 @@
       delete;
   ~MockAssistantViewDelegate() override;
 
-  MOCK_METHOD((const AssistantAlarmTimerModel*),
-              GetAlarmTimerModel,
-              (),
-              (const, override));
-
   MOCK_METHOD((const AssistantNotificationModel*),
               GetNotificationModel,
               (),
diff --git a/ash/public/cpp/assistant/controller/assistant_alarm_timer_controller.h b/ash/public/cpp/assistant/controller/assistant_alarm_timer_controller.h
index 99b600e..bf5f08bf 100644
--- a/ash/public/cpp/assistant/controller/assistant_alarm_timer_controller.h
+++ b/ash/public/cpp/assistant/controller/assistant_alarm_timer_controller.h
@@ -10,10 +10,13 @@
 #include <vector>
 
 #include "ash/public/cpp/ash_public_export.h"
+#include "base/optional.h"
 #include "base/time/time.h"
 
 namespace ash {
 
+class AssistantAlarmTimerModel;
+
 // Represents the current state of an Assistant timer.
 enum class AssistantTimerState {
   kUnknown,
@@ -40,6 +43,7 @@
   std::string id;
   std::string label;
   AssistantTimerState state{AssistantTimerState::kUnknown};
+  base::Optional<base::Time> creation_time;
   base::TimeDelta original_duration;
   base::Time fire_time;
   base::TimeDelta remaining_time;
@@ -58,8 +62,12 @@
       const AssistantAlarmTimerController&) = delete;
   virtual ~AssistantAlarmTimerController();
 
+  // Returns the singleton instance owned by AssistantController.
   static AssistantAlarmTimerController* Get();
 
+  // Returns a pointer to the underlying model.
+  virtual const AssistantAlarmTimerModel* GetModel() const = 0;
+
   // Invoked when timer state has changed. Note that |timers| may be empty.
   virtual void OnTimerStateChanged(std::vector<AssistantTimerPtr> timers) = 0;
 };
diff --git a/ash/strings/ash_strings_ar.xtb b/ash/strings/ash_strings_ar.xtb
index 6a2ed86..dcc92feb 100644
--- a/ash/strings/ash_strings_ar.xtb
+++ b/ash/strings/ash_strings_ar.xtb
@@ -536,7 +536,7 @@
 <translation id="7569509451529460200">‏تم تفعيل Braille وChromeVox</translation>
 <translation id="7593891976182323525">‏مفتاح البحث أو Shift</translation>
 <translation id="7600875258240007829">الاطّلاع على جميع الإشعارات</translation>
-<translation id="7624117708979618027"><ph name="TEMPERATURE_F" />° فهرنهايت</translation>
+<translation id="7624117708979618027"><ph name="TEMPERATURE_F" /> درجة فهرنهايت</translation>
 <translation id="7642647758716480637">فتح الإعدادات للشبكة <ph name="NETWORK_NAME" />،<ph name="CONNECTION_STATUS" /></translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (المالك)</translation>
 <translation id="7647488630410863958">فتح قفل الجهاز لعرض الإشعارات</translation>
diff --git a/ash/strings/ash_strings_es-419.xtb b/ash/strings/ash_strings_es-419.xtb
index dbe364c2..6ce000b4 100644
--- a/ash/strings/ash_strings_es-419.xtb
+++ b/ash/strings/ash_strings_es-419.xtb
@@ -63,6 +63,7 @@
 <translation id="1654477262762802994">Iniciar una búsqueda por voz</translation>
 <translation id="1658406695958299976">Todavía no se pudo verificar tu contraseña. Ten en cuenta que, si cambiaste tu contraseña recientemente, podrás usar la nueva cuando salgas. Aquí deberás usar la contraseña anterior.</translation>
 <translation id="1677472565718498478">Tiempo restante <ph name="TIME" /></translation>
+<translation id="1698080062160024910">Temporizador: <ph name="TOTAL_TIME" /> · <ph name="LABEL" /></translation>
 <translation id="1698760176351776263">Dirección IPv6: <ph name="ADDRESS" /></translation>
 <translation id="1709762881904163296">Configuración de red</translation>
 <translation id="1743570585616704562">No se reconoció</translation>
@@ -336,6 +337,7 @@
 <translation id="4924411785043111640">Reiniciar y restablecer</translation>
 <translation id="495046168593986294">Desplazar hacia arriba</translation>
 <translation id="4961318399572185831">Transmitir pantalla</translation>
+<translation id="4969092041573468113"><ph name="HOURS" /> h <ph name="MINUTES" /> min <ph name="SECONDS" /> s</translation>
 <translation id="5030687792513154421">Se acabó el tiempo</translation>
 <translation id="5035236842988137213">Se conectó el dispositivo <ph name="DEVICE_NAME" /> a un teléfono nuevo</translation>
 <translation id="5035389544768382859">Confirma la configuración de la pantalla</translation>
@@ -620,10 +622,12 @@
 <translation id="8517041960877371778">Tu <ph name="DEVICE_TYPE" /> podría no cargarse si el dispositivo está encendido.</translation>
 <translation id="8563862697512465947">Configuración de notificación</translation>
 <translation id="857201607579416096">El menú se movió a la esquina inferior derecha de la pantalla.</translation>
+<translation id="8594115950068821369">-<ph name="FORMATTED_TIME" /></translation>
 <translation id="8627191004499078455">Conectado a <ph name="DEVICE_NAME" /></translation>
 <translation id="8631727435199967028">Configuración de accesibilidad</translation>
 <translation id="8637598503828012618"><ph name="CONNECTION_STATUS" />, intensidad de la señal: <ph name="SIGNAL_STRENGTH" />, administrada por tu administrador</translation>
 <translation id="8639760480004882931"><ph name="PERCENTAGE" /> restante</translation>
+<translation id="8646417893960517480">Temporizador: <ph name="TOTAL_TIME" /></translation>
 <translation id="8649101189709089199">Seleccionar para pronunciar</translation>
 <translation id="8652175077544655965">Cerrar configuración</translation>
 <translation id="8653151467777939995">Mostrar la configuración de las notificaciones: Están activadas</translation>
diff --git a/ash/strings/ash_strings_ne.xtb b/ash/strings/ash_strings_ne.xtb
index cea8c67..96b36b1 100644
--- a/ash/strings/ash_strings_ne.xtb
+++ b/ash/strings/ash_strings_ne.xtb
@@ -63,6 +63,7 @@
 <translation id="1654477262762802994">आवाजमार्फत गरिने क्वेरी सुरु गर्नुहोस्</translation>
 <translation id="1658406695958299976">माफ गर्नुहोस्, तपाईंको पासवर्ड अझै प्रमाणित गर्न सकिएन। टिपोट: तपाईंले हालसालै आफ्नो पासवर्ड परिवर्तन गर्नुभएको खण्डमा तपाईं साइन आउट हुनेबित्तिकै तपाईंको नयाँ पासवर्ड लागू हुनेछ, कृपया यहाँ पुरानै पासवर्ड प्रयोग गर्नुहोस्।</translation>
 <translation id="1677472565718498478"><ph name="TIME" /> बाँकी छ</translation>
+<translation id="1698080062160024910"><ph name="TOTAL_TIME" /> टाइमर · <ph name="LABEL" /></translation>
 <translation id="1698760176351776263">IPv6 ठेगाना: <ph name="ADDRESS" /></translation>
 <translation id="1709762881904163296">नेटवर्कसम्बन्धी सेटिङहरू</translation>
 <translation id="1743570585616704562">पहिचान भएन</translation>
@@ -335,6 +336,7 @@
 <translation id="4924411785043111640">पुनः सुरु गरी रिसेट गर्नुहोस्</translation>
 <translation id="495046168593986294">माथि स्क्रोल गर्नुहोस्</translation>
 <translation id="4961318399572185831">स्क्रिन cast गर्नुहोस्</translation>
+<translation id="4969092041573468113"><ph name="HOURS" />घन्टा <ph name="MINUTES" />मिनेट <ph name="SECONDS" />सेकेन्ड</translation>
 <translation id="5030687792513154421">समय सकियो</translation>
 <translation id="5035236842988137213"><ph name="DEVICE_NAME" /> कुनै नयाँ फोनसँग जोडियो</translation>
 <translation id="5035389544768382859">डिस्प्ले कन्फिगुरेसन पुष्टि गर्नुहोस्</translation>
@@ -619,10 +621,12 @@
 <translation id="8517041960877371778">खुला हुँदा तपाईँको <ph name="DEVICE_TYPE" /> चार्ज नहुन सक्छ।</translation>
 <translation id="8563862697512465947">सूचनाका सेटिङहरू</translation>
 <translation id="857201607579416096">मेनु सारेर स्क्रिनको फेदको दायाँ कुनामा लगियो।</translation>
+<translation id="8594115950068821369">-<ph name="FORMATTED_TIME" /></translation>
 <translation id="8627191004499078455"><ph name="DEVICE_NAME" /> मा जोडियो</translation>
 <translation id="8631727435199967028">पहुँचसम्बन्धी सेटिङहरू</translation>
 <translation id="8637598503828012618"><ph name="CONNECTION_STATUS" />, सिग्नलको क्षमता <ph name="SIGNAL_STRENGTH" />, तपाईंका प्रशासकले व्यवस्थित गर्नुभएको छ</translation>
 <translation id="8639760480004882931"><ph name="PERCENTAGE" /> बाँकी छ</translation>
+<translation id="8646417893960517480"><ph name="TOTAL_TIME" /> टाइमर</translation>
 <translation id="8649101189709089199">चयन गरेर बोल्ने सुविधा</translation>
 <translation id="8652175077544655965">सेटिङहरू बन्द गर्नुहोस्</translation>
 <translation id="8653151467777939995">सूचनासम्बन्धी सेटिङहरू देखाउनुहोस्। सूचनाहरू सक्रिय छन्</translation>
diff --git a/ash/strings/ash_strings_zh-TW.xtb b/ash/strings/ash_strings_zh-TW.xtb
index 9bf41f9..ed033ca 100644
--- a/ash/strings/ash_strings_zh-TW.xtb
+++ b/ash/strings/ash_strings_zh-TW.xtb
@@ -63,6 +63,7 @@
 <translation id="1654477262762802994">啟動語音查詢</translation>
 <translation id="1658406695958299976">很抱歉,系統仍然無法驗證你的密碼。注意:如果你的密碼最近有所異動,新密碼會在你登出後立即生效,目前請在這裡使用舊密碼。</translation>
 <translation id="1677472565718498478"><ph name="TIME" /> 後用盡</translation>
+<translation id="1698080062160024910"><ph name="TOTAL_TIME" />的計時器 · <ph name="LABEL" /></translation>
 <translation id="1698760176351776263">IPv6 位址:<ph name="ADDRESS" /></translation>
 <translation id="1709762881904163296">網路設定</translation>
 <translation id="1743570585616704562">無法識別</translation>
@@ -335,6 +336,7 @@
 <translation id="4924411785043111640">重新啟動並重設</translation>
 <translation id="495046168593986294">向上捲動</translation>
 <translation id="4961318399572185831">投放螢幕</translation>
+<translation id="4969092041573468113"><ph name="HOURS" /> 小時 <ph name="MINUTES" /> 分鐘 <ph name="SECONDS" /> 秒</translation>
 <translation id="5030687792513154421">使用時間結束</translation>
 <translation id="5035236842988137213"><ph name="DEVICE_NAME" /> 已連結到新手機</translation>
 <translation id="5035389544768382859">確認螢幕設定</translation>
@@ -619,10 +621,12 @@
 <translation id="8517041960877371778"><ph name="DEVICE_TYPE" /> 在開啟時可能無法充電。</translation>
 <translation id="8563862697512465947">通知設定</translation>
 <translation id="857201607579416096">已將選單移至畫面右下角。</translation>
+<translation id="8594115950068821369">-<ph name="FORMATTED_TIME" /></translation>
 <translation id="8627191004499078455">已連線至<ph name="DEVICE_NAME" /></translation>
 <translation id="8631727435199967028">無障礙設定</translation>
 <translation id="8637598503828012618"><ph name="CONNECTION_STATUS" />,訊號強度 <ph name="SIGNAL_STRENGTH" />,由系統管理員管理</translation>
 <translation id="8639760480004882931">剩餘電量:<ph name="PERCENTAGE" /></translation>
+<translation id="8646417893960517480"><ph name="TOTAL_TIME" />的計時器</translation>
 <translation id="8649101189709089199">隨選朗讀</translation>
 <translation id="8652175077544655965">關閉設定</translation>
 <translation id="8653151467777939995">顯示通知設定。已開啟所有通知</translation>
diff --git a/ash/system/model/virtual_keyboard_model.cc b/ash/system/model/virtual_keyboard_model.cc
index d621f3f..d2727d5 100644
--- a/ash/system/model/virtual_keyboard_model.cc
+++ b/ash/system/model/virtual_keyboard_model.cc
@@ -33,6 +33,7 @@
 
 void VirtualKeyboardModel::OnArcInputMethodBoundsChanged(
     const gfx::Rect& bounds) {
+  arc_keyboard_bounds_ = bounds;
   const bool new_visible = !bounds.IsEmpty();
   if (visible_ == new_visible)
     return;
diff --git a/ash/system/model/virtual_keyboard_model.h b/ash/system/model/virtual_keyboard_model.h
index c172897..eeaa1cf 100644
--- a/ash/system/model/virtual_keyboard_model.h
+++ b/ash/system/model/virtual_keyboard_model.h
@@ -41,6 +41,7 @@
   void OnArcInputMethodBoundsChanged(const gfx::Rect& bounds) override;
 
   bool visible() const { return visible_; }
+  const gfx::Rect& arc_keyboard_bounds() const { return arc_keyboard_bounds_; }
 
  private:
   void NotifyChanged();
@@ -48,6 +49,8 @@
   // The visibility of virtual keyboard.
   bool visible_ = false;
 
+  gfx::Rect arc_keyboard_bounds_;
+
   base::ObserverList<Observer>::Unchecked observers_;
 
   DISALLOW_COPY_AND_ASSIGN(VirtualKeyboardModel);
diff --git a/ash/wm/desks/desks_controller.cc b/ash/wm/desks/desks_controller.cc
index e958147..55ade6f 100644
--- a/ash/wm/desks/desks_controller.cc
+++ b/ash/wm/desks/desks_controller.cc
@@ -7,7 +7,7 @@
 #include <utility>
 
 #include "ash/accessibility/accessibility_controller_impl.h"
-#include "ash/public/cpp/fps_counter.h"
+#include "ash/public/cpp/metrics_util.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
@@ -34,6 +34,7 @@
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/compositor/compositor.h"
+#include "ui/compositor/throughput_tracker.h"
 #include "ui/wm/public/activation_client.h"
 
 namespace ash {
@@ -90,8 +91,7 @@
   }
 }
 
-// Selects and returns the compositor that the FpsCounter will use to measure
-// the animation smoothness.
+// Selects and returns the compositor to measure the animation smoothness.
 ui::Compositor* GetSelectedCompositorForAnimationSmoothness() {
   // Favor the compositor associated with the active window's root window (if
   // any), or that of the primary root window.
@@ -140,8 +140,7 @@
     for (auto& observer : controller_->observers_)
       observer.OnDeskSwitchAnimationLaunching();
 
-    fps_counter_ = std::make_unique<FpsCounter>(
-        GetSelectedCompositorForAnimationSmoothness());
+    throughput_tracker_.Start(GetReportCallback());
 
     // This step makes sure that the containers of the target desk are shown at
     // the beginning of the animation (but not actually visible to the user yet,
@@ -214,7 +213,7 @@
 
     desk_switch_animators_.clear();
 
-    ComputeAnimationSmoothnessAndReport();
+    throughput_tracker_.Stop();
 
     for (auto& observer : controller_->observers_)
       observer.OnDeskSwitchAnimationFinished();
@@ -240,9 +239,10 @@
 
   // Since performance here matters, we have to use the UMA histograms macros to
   // report the smoothness histograms, but each macro use has to be associated
-  // with exactly one histogram name. This function allows subclasses to report
-  // the histogram using the macro with their desired name.
-  virtual void ReportSmoothness(int smoothness) const = 0;
+  // with exactly one histogram name. This function allows subclasses to return
+  // a callback that reports the histogram using the macro with their desired
+  // name.
+  virtual ash::metrics_util::ReportCallback GetReportCallback() const = 0;
 
   DesksController* const controller_;
 
@@ -255,17 +255,10 @@
   const Desk* const ending_desk_;
 
  private:
-  // Computes the animation smoothness and reports an UMA stat for it.
-  void ComputeAnimationSmoothnessAndReport() {
-    DCHECK(fps_counter_);
-    const int smoothness = fps_counter_->ComputeSmoothness();
-    if (smoothness < 0)
-      return;
-    ReportSmoothness(smoothness);
-  }
-
-  // The FPS counter used for measuring this animation smoothness.
-  std::unique_ptr<FpsCounter> fps_counter_;
+  // ThroughputTracker used for measuring this animation smoothness.
+  ui::ThroughputTracker throughput_tracker_ =
+      GetSelectedCompositorForAnimationSmoothness()
+          ->RequestNewThroughputTracker();
 
   DISALLOW_COPY_AND_ASSIGN(DeskAnimationBase);
 };
@@ -323,9 +316,12 @@
 
   void OnDeskSwitchAnimationFinishedInternal() override {}
 
-  void ReportSmoothness(int smoothness) const override {
-    UMA_HISTOGRAM_PERCENTAGE(kDeskActivationSmoothnessHistogramName,
-                             smoothness);
+  ash::metrics_util::ReportCallback GetReportCallback() const override {
+    return ash::metrics_util::ForSmoothness(
+        base::BindRepeating([](int smoothness) {
+          UMA_HISTOGRAM_PERCENTAGE(kDeskActivationSmoothnessHistogramName,
+                                   smoothness);
+        }));
   }
 
  private:
@@ -388,8 +384,12 @@
     MaybeRestoreSplitView(/*refresh_snapped_windows=*/true);
   }
 
-  void ReportSmoothness(int smoothness) const override {
-    UMA_HISTOGRAM_PERCENTAGE(kDeskRemovalSmoothnessHistogramName, smoothness);
+  ash::metrics_util::ReportCallback GetReportCallback() const override {
+    return ash::metrics_util::ForSmoothness(
+        base::BindRepeating([](int smoothness) {
+          UMA_HISTOGRAM_PERCENTAGE(kDeskRemovalSmoothnessHistogramName,
+                                   smoothness);
+        }));
   }
 
  private:
diff --git a/ash/wm/gestures/back_gesture/back_gesture_event_handler.cc b/ash/wm/gestures/back_gesture/back_gesture_event_handler.cc
index f0939f6..ab38bdc 100644
--- a/ash/wm/gestures/back_gesture/back_gesture_event_handler.cc
+++ b/ash/wm/gestures/back_gesture/back_gesture_event_handler.cc
@@ -8,12 +8,15 @@
 #include "ash/display/screen_orientation_controller.h"
 #include "ash/home_screen/home_screen_controller.h"
 #include "ash/keyboard/keyboard_util.h"
+#include "ash/keyboard/ui/keyboard_ui_controller.h"
 #include "ash/public/cpp/app_types.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shelf/contextual_tooltip.h"
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
+#include "ash/system/model/system_tray_model.h"
+#include "ash/system/model/virtual_keyboard_model.h"
 #include "ash/wm/gestures/back_gesture/back_gesture_affordance.h"
 #include "ash/wm/gestures/back_gesture/back_gesture_contextual_nudge_controller_impl.h"
 #include "ash/wm/overview/overview_controller.h"
@@ -43,6 +46,25 @@
   if (!IsCurrentScreenOrientationLandscape())
     return false;
 
+  // If virtual keyboard is visible when we swipe from the splitview divider
+  // area, do not allow go back if the location is inside of the virtual
+  // keyboard bounds.
+  auto* keyboard_controller = keyboard::KeyboardUIController::Get();
+  if (keyboard_controller->IsEnabled() &&
+      keyboard_controller->GetVisualBoundsInScreen().Contains(
+          screen_location)) {
+    return false;
+  }
+  // Same thing for ARC virtual keyboard as well.
+  SystemTrayModel* system_tray_model = Shell::Get()->system_tray_model();
+  if (system_tray_model) {
+    auto* arc_keyboard = system_tray_model->virtual_keyboard();
+    if (arc_keyboard->visible() &&
+        arc_keyboard->arc_keyboard_bounds().Contains(screen_location)) {
+      return false;
+    }
+  }
+
   auto* root_window = window_util::GetRootWindowAt(screen_location);
   auto* split_view_controller = SplitViewController::Get(root_window);
   if (!split_view_controller->InTabletSplitViewMode())
diff --git a/ash/wm/gestures/back_gesture/back_gesture_event_handler_unittest.cc b/ash/wm/gestures/back_gesture/back_gesture_event_handler_unittest.cc
index e1a64fc9..6a374bb 100644
--- a/ash/wm/gestures/back_gesture/back_gesture_event_handler_unittest.cc
+++ b/ash/wm/gestures/back_gesture/back_gesture_event_handler_unittest.cc
@@ -11,6 +11,7 @@
 #include "ash/display/screen_orientation_controller.h"
 #include "ash/display/screen_orientation_controller_test_api.h"
 #include "ash/home_screen/home_screen_controller.h"
+#include "ash/keyboard/ui/keyboard_ui_controller.h"
 #include "ash/keyboard/ui/test/keyboard_test_util.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/keyboard/keyboard_controller.h"
@@ -584,6 +585,70 @@
   EXPECT_EQ(1, target_back_release.accelerator_count());
 }
 
+// Tests when back performs on the split view divider bar inside or outside of
+// virtual keyboard.
+TEST_F(BackGestureEventHandlerTest,
+       BackGestureWithCrosKeyboardInSplitViewTest) {
+  ui::TestAcceleratorTarget target_back_press, target_back_release;
+  RegisterBackPressAndRelease(&target_back_press, &target_back_release);
+
+  std::unique_ptr<aura::Window> left_window = CreateTestWindow();
+  std::unique_ptr<aura::Window> right_window = CreateTestWindow();
+  auto* split_view_controller =
+      SplitViewController::Get(Shell::GetPrimaryRootWindow());
+  split_view_controller->SnapWindow(left_window.get(),
+                                    SplitViewController::LEFT);
+  split_view_controller->SnapWindow(right_window.get(),
+                                    SplitViewController::RIGHT);
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller->state());
+
+  KeyboardController* keyboard_controller = KeyboardController::Get();
+  keyboard_controller->SetEnableFlag(
+      keyboard::KeyboardEnableFlag::kExtensionEnabled);
+  // The keyboard needs to be in a loaded state before being shown.
+  ASSERT_TRUE(keyboard::test::WaitUntilLoaded());
+  keyboard_controller->ShowKeyboard();
+  EXPECT_TRUE(keyboard_controller->IsKeyboardVisible());
+
+  // Get the keyboard bounds:
+  keyboard::KeyboardUIController* keyboard_ui_controller =
+      keyboard::KeyboardUIController::Get();
+  EXPECT_TRUE(keyboard_ui_controller->IsKeyboardVisible());
+  gfx::Rect keyboard_bounds = keyboard_ui_controller->GetVisualBoundsInScreen();
+
+  // Start drag from splitview divider bar position outside VK bounds.
+  gfx::Rect divider_bounds =
+      split_view_controller->split_view_divider()->GetDividerBoundsInScreen(
+          false);
+  gfx::Point start = gfx::Point(divider_bounds.CenterPoint().x(), 10);
+  gfx::Point end =
+      gfx::Point(start.x() + kSwipingDistanceForGoingBack + 10, start.y());
+  GetEventGenerator()->GestureScrollSequence(
+      start, end, base::TimeDelta::FromMilliseconds(100), 3);
+  // Virtual keyboard should be closed.
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller->state());
+  EXPECT_FALSE(keyboard_controller->IsKeyboardVisible());
+  EXPECT_EQ(0, target_back_press.accelerator_count());
+  EXPECT_EQ(0, target_back_release.accelerator_count());
+
+  // Start drag from splitview divider bar position inside VK bounds.
+  keyboard_controller->ShowKeyboard();
+  EXPECT_TRUE(keyboard_controller->IsKeyboardVisible());
+  start = gfx::Point(divider_bounds.CenterPoint().x(),
+                     keyboard_bounds.CenterPoint().y());
+  end = gfx::Point(start.x() + kSwipingDistanceForGoingBack + 10, start.y());
+  GetEventGenerator()->GestureScrollSequence(
+      start, end, base::TimeDelta::FromMilliseconds(100), 3);
+  // Nothing should happen.
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller->state());
+  EXPECT_TRUE(keyboard_controller->IsKeyboardVisible());
+  EXPECT_EQ(0, target_back_press.accelerator_count());
+  EXPECT_EQ(0, target_back_release.accelerator_count());
+}
+
 // Tests the back gesture behavior when an Android IME is visible. Due to the
 // way the Android IME is implemented, a lot of this test is fake behavior, but
 // it will help catch regressions.
@@ -610,6 +675,72 @@
   EXPECT_FALSE(window_state->IsMinimized());
 }
 
+// Tests when back performs on the split view divider bar inside or outside of
+// android virtual keyboard.
+TEST_F(BackGestureEventHandlerTest,
+       BackGestureWithAndroidKeyboardInSplitViewTest) {
+  UpdateDisplay("800x600");
+  ui::TestAcceleratorTarget target_back_press, target_back_release;
+  RegisterBackPressAndRelease(&target_back_press, &target_back_release);
+
+  std::unique_ptr<aura::Window> left_window = CreateTestWindow();
+  std::unique_ptr<aura::Window> right_window = CreateTestWindow();
+  auto* split_view_controller =
+      SplitViewController::Get(Shell::GetPrimaryRootWindow());
+  split_view_controller->SnapWindow(left_window.get(),
+                                    SplitViewController::LEFT);
+  split_view_controller->SnapWindow(right_window.get(),
+                                    SplitViewController::RIGHT);
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller->state());
+
+  VirtualKeyboardModel* keyboard =
+      Shell::Get()->system_tray_model()->virtual_keyboard();
+  ASSERT_TRUE(keyboard);
+  // Fakes showing the keyboard.
+  gfx::Rect keyboard_bounds =
+      screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
+          left_window.get());
+  keyboard_bounds.set_y(keyboard_bounds.bottom() - 200);
+  keyboard_bounds.set_height(200);
+  keyboard->OnArcInputMethodBoundsChanged(keyboard_bounds);
+  EXPECT_TRUE(keyboard->visible());
+
+  // Start drag from splitview divider bar position outside VK bounds.
+  gfx::Rect divider_bounds =
+      split_view_controller->split_view_divider()->GetDividerBoundsInScreen(
+          false);
+  gfx::Point start = gfx::Point(divider_bounds.CenterPoint().x(), 10);
+  gfx::Point end =
+      gfx::Point(start.x() + kSwipingDistanceForGoingBack + 10, start.y());
+  GetEventGenerator()->GestureScrollSequence(
+      start, end, base::TimeDelta::FromMilliseconds(100), 3);
+  // Virtual keyboard should be closed. But Unfortunately we cannot hook
+  // this all the wall up to see if the Android IME is hidden, but we can check
+  // that back key events are generated and we're still in both snapped split
+  // view state.
+  EXPECT_EQ(1, target_back_press.accelerator_count());
+  EXPECT_EQ(1, target_back_release.accelerator_count());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller->state());
+
+  // Start drag from splitview divider bar position inside VK bounds.
+  target_back_press.ResetCounts();
+  target_back_release.ResetCounts();
+  keyboard->OnArcInputMethodBoundsChanged(keyboard_bounds);
+  EXPECT_TRUE(keyboard->visible());
+  start = gfx::Point(divider_bounds.CenterPoint().x(),
+                     keyboard_bounds.CenterPoint().y());
+  end = gfx::Point(start.x() + kSwipingDistanceForGoingBack + 10, start.y());
+  GetEventGenerator()->GestureScrollSequence(
+      start, end, base::TimeDelta::FromMilliseconds(100), 3);
+  // Nothing should happen.
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller->state());
+  EXPECT_EQ(0, target_back_press.accelerator_count());
+  EXPECT_EQ(0, target_back_release.accelerator_count());
+}
+
 // Tests that swiping on the backdrop to minimize a non-resizable app will not
 // cause a crash. Regression test for http://crbug.com/1064618.
 TEST_F(BackGestureEventHandlerTestCantGoBack, NonResizableApp) {
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 4524b0d..9523677 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1030,7 +1030,6 @@
       "win/sphelper.h",
       "win/startup_information.cc",
       "win/startup_information.h",
-      "win/typed_event_handler.h",
       "win/vector.cc",
       "win/vector.h",
       "win/win_util.cc",
@@ -2953,7 +2952,6 @@
       "win/scoped_winrt_initializer_unittest.cc",
       "win/shortcut_unittest.cc",
       "win/startup_information_unittest.cc",
-      "win/typed_event_handler_unittest.cc",
       "win/vector_unittest.cc",
       "win/win_includes_unittest.cc",
       "win/win_util_unittest.cc",
diff --git a/base/allocator/partition_allocator/partition_address_space.h b/base/allocator/partition_allocator/partition_address_space.h
index 9a25728..153287f9 100644
--- a/base/allocator/partition_allocator/partition_address_space.h
+++ b/base/allocator/partition_allocator/partition_address_space.h
@@ -20,6 +20,8 @@
 // The address space reservation is supported only on 64-bit architecture.
 #if defined(ARCH_CPU_64_BITS)
 
+static_assert(sizeof(size_t) >= 8, "Need 64-bit address space");
+
 // Reserves address space for PartitionAllocator.
 class BASE_EXPORT PartitionAddressSpace {
  public:
@@ -58,11 +60,9 @@
   // | (unused)       |
   // +----------------+ reserved address end
 
-  static constexpr size_t kGigaBytes = static_cast<size_t>(1024 * 1024 * 1024);
-  static constexpr size_t kDirectMapPoolSize =
-      static_cast<size_t>(16 * kGigaBytes);
-  static constexpr size_t kNormalBucketPoolSize =
-      static_cast<size_t>(16 * kGigaBytes);
+  static constexpr size_t kGigaBytes = 1024 * 1024 * 1024;
+  static constexpr size_t kDirectMapPoolSize = 16 * kGigaBytes;
+  static constexpr size_t kNormalBucketPoolSize = 16 * kGigaBytes;
   // kSuperPageSize padding is added to be able to align to kSuperPageSize
   // boundary.
   static constexpr size_t kReservedAddressSpaceSize =
diff --git a/base/profiler/chrome_unwinder_android.cc b/base/profiler/chrome_unwinder_android.cc
index 8eea2a8..4e19111 100644
--- a/base/profiler/chrome_unwinder_android.cc
+++ b/base/profiler/chrome_unwinder_android.cc
@@ -13,16 +13,17 @@
 
 ChromeUnwinderAndroid::ChromeUnwinderAndroid(
     const ArmCFITable* cfi_table,
-    const ModuleCache::Module* chrome_module)
-    : cfi_table_(cfi_table), chrome_module_(chrome_module) {
+    uintptr_t chrome_module_base_address)
+    : cfi_table_(cfi_table),
+      chrome_module_base_address_(chrome_module_base_address) {
   DCHECK(cfi_table_);
-  DCHECK(chrome_module_);
 }
 
 ChromeUnwinderAndroid::~ChromeUnwinderAndroid() = default;
 
 bool ChromeUnwinderAndroid::CanUnwindFrom(const Frame& current_frame) const {
-  return current_frame.module == chrome_module_;
+  return current_frame.module &&
+         current_frame.module->GetBaseAddress() == chrome_module_base_address_;
 }
 
 UnwindResult ChromeUnwinderAndroid::TryUnwind(RegisterContext* thread_context,
diff --git a/base/profiler/chrome_unwinder_android.h b/base/profiler/chrome_unwinder_android.h
index b8f6789..6894380 100644
--- a/base/profiler/chrome_unwinder_android.h
+++ b/base/profiler/chrome_unwinder_android.h
@@ -19,7 +19,7 @@
 class BASE_EXPORT ChromeUnwinderAndroid : public Unwinder {
  public:
   ChromeUnwinderAndroid(const ArmCFITable* cfi_table,
-                        const ModuleCache::Module* chrome_module);
+                        uintptr_t chrome_module_base_address);
   ~ChromeUnwinderAndroid() override;
   ChromeUnwinderAndroid(const ChromeUnwinderAndroid&) = delete;
   ChromeUnwinderAndroid& operator=(const ChromeUnwinderAndroid&) = delete;
@@ -43,7 +43,7 @@
                    const ArmCFITable::FrameEntry& entry);
 
   const ArmCFITable* cfi_table_;
-  const ModuleCache::Module* const chrome_module_;
+  const uintptr_t chrome_module_base_address_;
 };
 
 }  // namespace base
diff --git a/base/profiler/chrome_unwinder_android_unittest.cc b/base/profiler/chrome_unwinder_android_unittest.cc
index e74a710..9e8b1bb4 100644
--- a/base/profiler/chrome_unwinder_android_unittest.cc
+++ b/base/profiler/chrome_unwinder_android_unittest.cc
@@ -213,7 +213,8 @@
   auto non_chrome_module =
       std::make_unique<TestModule>(0x2000, 0x500, "OtherModule");
 
-  ChromeUnwinderAndroid unwinder(cfi_table.get(), chrome_module.get());
+  ChromeUnwinderAndroid unwinder(cfi_table.get(),
+                                 chrome_module->GetBaseAddress());
 
   EXPECT_TRUE(unwinder.CanUnwindFrom({0x1100, chrome_module.get()}));
   EXPECT_FALSE(unwinder.CanUnwindFrom({0x2100, non_chrome_module.get()}));
@@ -227,7 +228,8 @@
   const ModuleCache::Module* chrome_module = AddNativeModule(
       &module_cache, std::make_unique<TestModule>(0x1000, 0x500));
 
-  ChromeUnwinderAndroid unwinder(cfi_table.get(), chrome_module);
+  ChromeUnwinderAndroid unwinder(cfi_table.get(),
+                                 chrome_module->GetBaseAddress());
 
   std::vector<uintptr_t> stack_buffer = {
       0xFFFF,
@@ -264,7 +266,8 @@
   const ModuleCache::Module* chrome_module = AddNativeModule(
       &module_cache, std::make_unique<TestModule>(0x1000, 0x500));
 
-  ChromeUnwinderAndroid unwinder(cfi_table.get(), chrome_module);
+  ChromeUnwinderAndroid unwinder(cfi_table.get(),
+                                 chrome_module->GetBaseAddress());
 
   std::vector<uintptr_t> stack_buffer = {
       0xFFFF,
@@ -295,7 +298,8 @@
   const ModuleCache::Module* chrome_module = AddNativeModule(
       &module_cache, std::make_unique<TestModule>(0x1000, 0x500));
 
-  ChromeUnwinderAndroid unwinder(cfi_table.get(), chrome_module);
+  ChromeUnwinderAndroid unwinder(cfi_table.get(),
+                                 chrome_module->GetBaseAddress());
 
   std::vector<uintptr_t> stack_buffer = {0xFFFF};
 
diff --git a/base/profiler/stack_sampling_profiler_test_util.cc b/base/profiler/stack_sampling_profiler_test_util.cc
index 1f2adec..3ea67f52 100644
--- a/base/profiler/stack_sampling_profiler_test_util.cc
+++ b/base/profiler/stack_sampling_profiler_test_util.cc
@@ -120,14 +120,14 @@
 }
 
 std::unique_ptr<Unwinder> CreateChromeUnwinderAndroidForTesting(
-    ModuleCache* module_cache) {
+    uintptr_t chrome_module_base_address) {
   static constexpr char kCfiFileName[] = "assets/unwind_cfi_32";
   class ChromeUnwinderAndroidForTesting : public ChromeUnwinderAndroid {
    public:
     ChromeUnwinderAndroidForTesting(std::unique_ptr<MemoryMappedFile> cfi_file,
                                     std::unique_ptr<ArmCFITable> cfi_table,
-                                    const ModuleCache::Module* chrome_module)
-        : ChromeUnwinderAndroid(cfi_table.get(), chrome_module),
+                                    uintptr_t chrome_module_base_address)
+        : ChromeUnwinderAndroid(cfi_table.get(), chrome_module_base_address),
           cfi_file_(std::move(cfi_file)),
           cfi_table_(std::move(cfi_table)) {}
     ~ChromeUnwinderAndroidForTesting() override = default;
@@ -150,9 +150,7 @@
     return nullptr;
 
   return std::make_unique<ChromeUnwinderAndroidForTesting>(
-      std::move(cfi_file), std::move(cfi_table),
-      module_cache->GetModuleForAddress(
-          reinterpret_cast<uintptr_t>(&__executable_start)));
+      std::move(cfi_file), std::move(cfi_table), chrome_module_base_address);
 }
 #endif  // #if defined(OS_ANDROID) && BUILDFLAG(ENABLE_ARM_CFI_TABLE)
 
@@ -422,7 +420,8 @@
   std::vector<std::unique_ptr<Unwinder>> unwinders;
   unwinders.push_back(CreateNativeUnwinderAndroidForTesting(
       reinterpret_cast<uintptr_t>(&__executable_start)));
-  unwinders.push_back(CreateChromeUnwinderAndroidForTesting(module_cache));
+  unwinders.push_back(CreateChromeUnwinderAndroidForTesting(
+      reinterpret_cast<uintptr_t>(&__executable_start)));
   return unwinders;
 #else
   return {};
diff --git a/base/trace_event/builtin_categories.h b/base/trace_event/builtin_categories.h
index 8f6f0840..e8b18bc 100644
--- a/base/trace_event/builtin_categories.h
+++ b/base/trace_event/builtin_categories.h
@@ -152,6 +152,7 @@
   X("ui")                                                                \
   X("v8")                                                                \
   X("v8.execute")                                                        \
+  X("v8.wasm")                                                           \
   X("ValueStoreFrontend::Backend")                                       \
   X("views")                                                             \
   X("views.frame")                                                       \
@@ -236,7 +237,7 @@
   X(TRACE_DISABLED_BY_DEFAULT("v8.runtime_stats"))                       \
   X(TRACE_DISABLED_BY_DEFAULT("v8.runtime_stats_sampling"))              \
   X(TRACE_DISABLED_BY_DEFAULT("v8.turbofan"))                            \
-  X(TRACE_DISABLED_BY_DEFAULT("v8.wasm"))                                \
+  X(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"))                       \
   X(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"))                \
   X(TRACE_DISABLED_BY_DEFAULT("viz.debug.overlay_planes"))               \
   X(TRACE_DISABLED_BY_DEFAULT("viz.hit_testing_flow"))                   \
diff --git a/base/win/async_operation_unittest.cc b/base/win/async_operation_unittest.cc
index b29e181..2309c230 100644
--- a/base/win/async_operation_unittest.cc
+++ b/base/win/async_operation_unittest.cc
@@ -56,6 +56,19 @@
   }
 };
 
+#ifdef NTDDI_WIN10_VB  // Windows 10.0.19041
+// Specialization templates that used to be in windows.foundation.h, removed in
+// the 10.0.19041.0 SDK, so placed here instead.
+template <>
+struct __declspec(uuid("968b9665-06ed-5774-8f53-8edeabd5f7b5"))
+    IAsyncOperation<int> : IAsyncOperation_impl<int> {};
+
+template <>
+struct __declspec(uuid("d60cae9d-88cb-59f1-8576-3fba44796be8"))
+    IAsyncOperationCompletedHandler<int>
+    : IAsyncOperationCompletedHandler_impl<int> {};
+#endif
+
 }  // namespace Foundation
 }  // namespace Windows
 }  // namespace ABI
diff --git a/base/win/reference_unittest.cc b/base/win/reference_unittest.cc
index 4116872..a83f3f5 100644
--- a/base/win/reference_unittest.cc
+++ b/base/win/reference_unittest.cc
@@ -9,6 +9,24 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 
+#ifdef NTDDI_WIN10_VB  // Windows 10.0.19041
+// Specialization templates that used to be in windows.foundation.h, removed in
+// the 10.0.19041.0 SDK, so placed here instead.
+namespace ABI {
+namespace Windows {
+namespace Foundation {
+template <>
+struct __declspec(uuid("3c00fd60-2950-5939-a21a-2d12c5a01b8a")) IReference<bool>
+    : IReference_impl<Internal::AggregateType<bool, boolean>> {};
+
+template <>
+struct __declspec(uuid("548cefbd-bc8a-5fa0-8df2-957440fc8bf4")) IReference<int>
+    : IReference_impl<int> {};
+}  // namespace Foundation
+}  // namespace Windows
+}  // namespace ABI
+#endif
+
 namespace base {
 namespace win {
 
diff --git a/base/win/typed_event_handler.h b/base/win/typed_event_handler.h
deleted file mode 100644
index fd62782..0000000
--- a/base/win/typed_event_handler.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_WIN_TYPED_EVENT_HANDLER_H_
-#define BASE_WIN_TYPED_EVENT_HANDLER_H_
-
-#include <windows.foundation.collections.h>
-#include <wrl/implements.h>
-
-#include <utility>
-
-#include "base/callback.h"
-
-namespace base {
-namespace win {
-
-// This file provides an implementation of Windows::Foundation's
-// ITypedEventHandler. It serves as a thin wrapper around a RepeatingCallback,
-// that forwards the arguments to its |Invoke| method to the callback's |Run|
-// method.
-template <typename SenderT, typename ArgsT>
-class TypedEventHandler
-    : public Microsoft::WRL::RuntimeClass<
-          Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
-          ABI::Windows::Foundation::ITypedEventHandler<SenderT, ArgsT>> {
- public:
-  using SenderAbiT =
-      typename ABI::Windows::Foundation::Internal::GetAbiType<SenderT>::type;
-  using ArgsAbiT =
-      typename ABI::Windows::Foundation::Internal::GetAbiType<ArgsT>::type;
-
-  using Handler = base::RepeatingCallback<HRESULT(SenderAbiT, ArgsAbiT)>;
-
-  explicit TypedEventHandler(Handler handler) : handler_(std::move(handler)) {}
-
-  // ABI::Windows::Foundation::ITypedEventHandler:
-  IFACEMETHODIMP Invoke(SenderAbiT sender, ArgsAbiT args) override {
-    return handler_.Run(std::move(sender), std::move(args));
-  }
-
- private:
-  Handler handler_;
-};
-
-}  // namespace win
-}  // namespace base
-
-#endif  // BASE_WIN_TYPED_EVENT_HANDLER_H_
diff --git a/base/win/typed_event_handler_unittest.cc b/base/win/typed_event_handler_unittest.cc
deleted file mode 100644
index 76dba80..0000000
--- a/base/win/typed_event_handler_unittest.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/win/typed_event_handler.h"
-
-#include <windows.foundation.h>
-
-#include "base/test/bind_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace win {
-
-TEST(TypedEventHandlerTest, InvokeSuccess) {
-  bool called_callback = false;
-  TypedEventHandler<IInspectable*, IInspectable*> handler(
-      base::BindLambdaForTesting([&](IInspectable* sender, IInspectable* args) {
-        EXPECT_EQ(reinterpret_cast<IInspectable*>(0x01), sender);
-        EXPECT_EQ(reinterpret_cast<IInspectable*>(0x02), args);
-        called_callback = true;
-        return S_OK;
-      }));
-
-  EXPECT_FALSE(called_callback);
-  HRESULT hr = handler.Invoke(reinterpret_cast<IInspectable*>(0x01),
-                              reinterpret_cast<IInspectable*>(0x02));
-  EXPECT_TRUE(called_callback);
-  EXPECT_EQ(S_OK, hr);
-}
-
-TEST(TypedEventHandlerTest, InvokeFail) {
-  bool called_callback = false;
-  TypedEventHandler<IInspectable*, IInspectable*> handler(
-      base::BindLambdaForTesting([&](IInspectable* sender, IInspectable* args) {
-        EXPECT_EQ(nullptr, sender);
-        EXPECT_EQ(nullptr, args);
-        called_callback = true;
-        return E_FAIL;
-      }));
-
-  EXPECT_FALSE(called_callback);
-  HRESULT hr = handler.Invoke(nullptr, nullptr);
-  EXPECT_TRUE(called_callback);
-  EXPECT_EQ(E_FAIL, hr);
-}
-
-}  // namespace win
-}  // namespace base
diff --git a/base/win/vector_unittest.cc b/base/win/vector_unittest.cc
index b2cce52..459e540 100644
--- a/base/win/vector_unittest.cc
+++ b/base/win/vector_unittest.cc
@@ -39,6 +39,43 @@
     VectorChangedEventHandler<Uri*>
     : VectorChangedEventHandler_impl<UriPtrAggregate> {};
 
+#ifdef NTDDI_WIN10_VB  // Windows 10.0.19041
+// Specialization templates that used to be in windows.foundation.h, removed in
+// the 10.0.19041.0 SDK, so placed here instead.
+template <>
+struct __declspec(uuid("b939af5b-b45d-5489-9149-61442c1905fe")) IVector<int>
+    : IVector_impl<int> {};
+
+template <>
+struct __declspec(uuid("8d720cdf-3934-5d3f-9a55-40e8063b086a")) IVectorView<int>
+    : IVectorView_impl<int> {};
+
+template <>
+struct __declspec(uuid("bfea7f78-50c2-5f1d-a6ea-9e978d2699ff")) IIterator<int>
+    : IIterator_impl<int> {};
+
+template <>
+struct __declspec(uuid("81a643fb-f51c-5565-83c4-f96425777b66")) IIterable<int>
+    : IIterable_impl<int> {};
+
+template <>
+struct __declspec(uuid("0d82bd8d-fe62-5d67-a7b9-7886dd75bc4e")) IVector<Uri*>
+    : IVector_impl<Internal::AggregateType<Uri*, IUriRuntimeClass*>> {};
+
+template <>
+struct __declspec(uuid("4b8385bd-a2cd-5ff1-bf74-7ea580423e50"))
+    IVectorView<Uri*>
+    : IVectorView_impl<Internal::AggregateType<Uri*, IUriRuntimeClass*>> {};
+
+template <>
+struct __declspec(uuid("1c157d0f-5efe-5cec-bbd6-0c6ce9af07a5")) IIterator<Uri*>
+    : IIterator_impl<Internal::AggregateType<Uri*, IUriRuntimeClass*>> {};
+
+template <>
+struct __declspec(uuid("b0d63b78-78ad-5e31-b6d8-e32a0e16c447")) IIterable<Uri*>
+    : IIterable_impl<Internal::AggregateType<Uri*, IUriRuntimeClass*>> {};
+#endif
+
 }  // namespace Collections
 }  // namespace Foundation
 }  // namespace Windows
diff --git a/build/android/gyp/java_cpp_strings.py b/build/android/gyp/java_cpp_strings.py
index acaaf22..498e05e3 100755
--- a/build/android/gyp/java_cpp_strings.py
+++ b/build/android/gyp/java_cpp_strings.py
@@ -114,6 +114,8 @@
       if string_line.groups()[1]:
         self._current_value = string_line.groups()[1]
         self._AppendString()
+      else:
+        self._in_string = True
       return True
     else:
       self._in_string = False
@@ -141,19 +143,19 @@
     return self._strings
 
 
-def _GenerateOutput(template, source_path, template_path, strings):
+def _GenerateOutput(template, source_paths, template_path, strings):
   description_template = """
     // This following string constants were inserted by
     //     {SCRIPT_NAME}
     // From
-    //     {SOURCE_PATH}
+    //     {SOURCE_PATHS}
     // Into
     //     {TEMPLATE_PATH}
 
 """
   values = {
       'SCRIPT_NAME': java_cpp_utils.GetScriptName(),
-      'SOURCE_PATH': source_path,
+      'SOURCE_PATHS': ',\n    //     '.join(source_paths),
       'TEMPLATE_PATH': template_path,
   }
   description = description_template.format(**values)
@@ -173,15 +175,18 @@
 def _Generate(source_paths, template_path):
   with open(template_path) as f:
     lines = f.readlines()
-    template = ''.join(lines)
-    for source_path in source_paths:
-      strings = _ParseStringFile(source_path)
-      package, class_name = ParseTemplateFile(lines)
-      package_path = package.replace('.', os.path.sep)
-      file_name = class_name + '.java'
-      output_path = os.path.join(package_path, file_name)
-      output = _GenerateOutput(template, source_path, template_path, strings)
-      yield output, output_path
+
+  template = ''.join(lines)
+  package, class_name = ParseTemplateFile(lines)
+  package_path = package.replace('.', os.path.sep)
+  file_name = class_name + '.java'
+  output_path = os.path.join(package_path, file_name)
+  strings = []
+  for source_path in source_paths:
+    strings.extend(_ParseStringFile(source_path))
+
+  output = _GenerateOutput(template, source_paths, template_path, strings)
+  return output, output_path
 
 
 def _Main(argv):
@@ -205,8 +210,8 @@
 
   with build_utils.AtomicOutput(args.srcjar) as f:
     with zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) as srcjar:
-      for data, path in _Generate(args.inputs, args.template):
-        build_utils.AddToZipHermetic(srcjar, path, data=data)
+      data, path = _Generate(args.inputs, args.template)
+      build_utils.AddToZipHermetic(srcjar, path, data=data)
 
 
 if __name__ == '__main__':
diff --git a/build/android/gyp/java_cpp_strings_tests.py b/build/android/gyp/java_cpp_strings_tests.py
index acf51e4..3b7d5ca 100755
--- a/build/android/gyp/java_cpp_strings_tests.py
+++ b/build/android/gyp/java_cpp_strings_tests.py
@@ -51,6 +51,10 @@
 const char kAString[] = "a-value";
 const char kNoComment[] = "no-comment";
 
+namespace myfeature {
+const char kMyFeatureNoComment[] = "myfeature.no-comment";
+}
+
 // Single line switch with a big space.
 const char kAStringWithSpace[]                      = "a-value";
 
@@ -58,23 +62,34 @@
 const char kAStringWithAVeryLongNameThatWillHaveToWrap[] =
     "a-string-with-a-very-long-name-that-will-have-to-wrap";
 
+// This one has no comment before it.
+
+const char kAStringWithAVeryLongNameThatWillHaveToWrap2[] =
+    "a-string-with-a-very-long-name-that-will-have-to-wrap2";
+
 // This is erroneous and should be ignored.
 const char kInvalidLineBreak[] =
 
     "invalid-line-break";
 """.split('\n')
     strings = java_cpp_strings.StringFileParser(test_data).Parse()
-    self.assertEqual(4, len(strings))
+    self.assertEqual(5, len(strings))
     self.assertEqual('A_STRING', strings[0].name)
     self.assertEqual('"a-value"', strings[0].value)
     self.assertEqual('NO_COMMENT', strings[1].name)
     self.assertEqual('"no-comment"', strings[1].value)
-    self.assertEqual('A_STRING_WITH_SPACE', strings[2].name)
-    self.assertEqual('"a-value"', strings[2].value)
+    self.assertEqual('MY_FEATURE_NO_COMMENT', strings[2].name)
+    self.assertEqual('"myfeature.no-comment"', strings[2].value)
+    self.assertEqual('A_STRING_WITH_SPACE', strings[3].name)
+    self.assertEqual('"a-value"', strings[3].value)
     self.assertEqual('A_STRING_WITH_A_VERY_LONG_NAME_THAT_WILL_HAVE_TO_WRAP',
-                     strings[3].name)
+                     strings[4].name)
     self.assertEqual('"a-string-with-a-very-long-name-that-will-have-to-wrap"',
-                     strings[3].value)
+                     strings[4].value)
+    self.assertEqual('A_STRING_WITH_A_VERY_LONG_NAME_THAT_WILL_HAVE_TO_WRAP2',
+                     strings[5].name)
+    self.assertEqual('"a-string-with-a-very-long-name-that-will-have-to-wrap2"',
+                     strings[5].value)
 
   def testTemplateParsing(self):
     test_data = """
diff --git a/build/fuchsia/emu_target.py b/build/fuchsia/emu_target.py
index 4e2f0b9..aca332ed 100644
--- a/build/fuchsia/emu_target.py
+++ b/build/fuchsia/emu_target.py
@@ -74,7 +74,7 @@
                                          env=emu_env)
 
     try:
-      self._WaitUntilReady();
+      self._WaitUntilReady(ssh_diagnostic_log_file=stdout);
     except target.FuchsiaTargetException:
       if temporary_system_log_file:
         logging.info('Kernel logs:\n' +
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 91e4690f..6dd4dc8 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20200604.2.1
+0.20200605.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 91e4690f..6dd4dc8 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20200604.2.1
+0.20200605.1.1
diff --git a/build/fuchsia/target.py b/build/fuchsia/target.py
index d8c1741f..56a16e1d 100644
--- a/build/fuchsia/target.py
+++ b/build/fuchsia/target.py
@@ -211,20 +211,28 @@
   def _AssertIsStarted(self):
     assert self.IsStarted()
 
-  def _WaitUntilReady(self):
+  def _WaitUntilReady(self, ssh_diagnostic_log_file=None):
     logging.info('Connecting to Fuchsia using SSH.')
 
+    if ssh_diagnostic_log_file is None:
+      ssh_diagnostic_log_file = open(os.devnull, 'w')
+
     host, port = self._GetEndpoint()
     end_time = time.time() + _ATTACH_RETRY_SECONDS
     while time.time() < end_time:
       runner = remote_cmd.CommandRunner(self._GetSshConfigPath(), host, port)
-      if runner.RunCommand(['true'], True) == 0:
+      ssh_proc = runner.RunCommandPiped(['true'],
+                                        ssh_args=['-v'],
+                                        stdout=ssh_diagnostic_log_file,
+                                        stderr=subprocess.STDOUT)
+      if ssh_proc.wait() == 0:
         logging.info('Connected!')
         self._started = True
         return True
       time.sleep(_ATTACH_RETRY_INTERVAL)
 
     logging.error('Timeout limit reached.')
+    log_file.flush()
 
     raise FuchsiaTargetException('Couldn\'t connect using SSH.')
 
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 461caf14..739baf6a 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -1443,7 +1443,7 @@
 
   java_cpp_enum("download_enum_javagen") {
     sources = [
-      "browser/download/download_location_dialog_type.h",
+      "browser/download/download_dialog_types.h",
       "browser/download/download_prompt_status.h",
     ]
   }
diff --git a/chrome/VERSION b/chrome/VERSION
index 42886b38..37de60ae 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=85
 MINOR=0
-BUILD=4165
+BUILD=4166
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index c61bc6a6..fd66d51 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -746,6 +746,8 @@
     "//chrome/browser/preferences:java",
     "//chrome/browser/preferences:preferences_junit_tests",
     "//chrome/browser/profiles/android:java",
+    "//chrome/browser/safety_check/android:java",
+    "//chrome/browser/safety_check/android:junit",
     "//chrome/browser/tab:java",
     "//chrome/browser/tabmodel:java",
     "//chrome/browser/thumbnail:java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 569a97f..fc79998 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -327,7 +327,6 @@
   "javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/CurrencyFormatterTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/ExpandablePaymentHandlerChangePaymentMethodTest.java",
-  "javatests/src/org/chromium/chrome/browser/payments/ExpandablePaymentHandlerCoordinatorTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/ExpandablePaymentHandlerTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/IsReadyToPayServiceHelperTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/MockPackageManagerDelegate.java",
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantGenericUiDelegate.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantGenericUiDelegate.java
index 28209dc..fbad6014 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantGenericUiDelegate.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantGenericUiDelegate.java
@@ -47,6 +47,12 @@
                 popupIdentifier);
     }
 
+    void onViewContainerCleared(String viewIdentifier) {
+        assert mNativeAssistantGenericUiDelegate != 0;
+        AssistantGenericUiDelegateJni.get().onViewContainerCleared(
+                mNativeAssistantGenericUiDelegate, AssistantGenericUiDelegate.this, viewIdentifier);
+    }
+
     @CalledByNative
     private void clearNativePtr() {
         mNativeAssistantGenericUiDelegate = 0;
@@ -62,5 +68,7 @@
                 long nativeAssistantGenericUiDelegate, AssistantGenericUiDelegate caller, int link);
         void onGenericPopupDismissed(long nativeAssistantGenericUiDelegate,
                 AssistantGenericUiDelegate caller, String popupIdentifier);
+        void onViewContainerCleared(long nativeAssistantGenericUiDelegate,
+                AssistantGenericUiDelegate caller, String viewIdentifier);
     }
 }
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantViewInteractions.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantViewInteractions.java
index 3ca4609..1ffabd7 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantViewInteractions.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantViewInteractions.java
@@ -9,6 +9,7 @@
 import android.content.Context;
 import android.text.TextUtils;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.TextView;
 
 import androidx.annotation.Nullable;
@@ -146,4 +147,27 @@
                 .setOnDismissListener(unused -> delegate.onGenericPopupDismissed(popupIdentifier))
                 .show();
     }
+
+    @CalledByNative
+    private static boolean clearViewContainer(
+            View container, String viewIdentifier, AssistantGenericUiDelegate delegate) {
+        if (!(container instanceof ViewGroup)) {
+            return false;
+        }
+        ((ViewGroup) container).removeAllViews();
+        delegate.onViewContainerCleared(viewIdentifier);
+        return true;
+    }
+
+    @CalledByNative
+    private static boolean attachViewToParent(View parent, View view) {
+        if (view == null || !(parent instanceof ViewGroup)) {
+            return false;
+        }
+        if (view.getParent() != null) {
+            return false;
+        }
+        ((ViewGroup) parent).addView(view);
+        return true;
+    }
 }
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantAccessibilityIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantAccessibilityIntegrationTest.java
index 015a51d..8944bb7 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantAccessibilityIntegrationTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantAccessibilityIntegrationTest.java
@@ -117,12 +117,17 @@
 
         // Show an element on top that should not be covered by the bottom sheet.
         SelectorProto element =
-                (SelectorProto) SelectorProto.newBuilder().addSelectors("#touch_area_one").build();
+                (SelectorProto) SelectorProto.newBuilder()
+                        .addFilters(
+                                SelectorProto.Filter.newBuilder().setCssSelector("#touch_area_one"))
+                        .build();
         ElementAreaProto elementArea =
                 (ElementAreaProto) ElementAreaProto.newBuilder()
                         .addTouchable(Rectangle.newBuilder().addElements(element))
                         .addTouchable(Rectangle.newBuilder().addElements(
-                                SelectorProto.newBuilder().addSelectors("#touch_area_four")))
+                                SelectorProto.newBuilder().addFilters(
+                                        SelectorProto.Filter.newBuilder().setCssSelector(
+                                                "#touch_area_four"))))
                         .build();
         list.add((ActionProto) ActionProto.newBuilder()
                          .setFocusElement(FocusElementProto.newBuilder()
@@ -188,12 +193,17 @@
 
         // Show an element on top that may or may not be covered by the bottom sheet.
         SelectorProto element =
-                (SelectorProto) SelectorProto.newBuilder().addSelectors("#touch_area_one").build();
+                (SelectorProto) SelectorProto.newBuilder()
+                        .addFilters(
+                                SelectorProto.Filter.newBuilder().setCssSelector("#touch_area_one"))
+                        .build();
         ElementAreaProto elementArea =
                 (ElementAreaProto) ElementAreaProto.newBuilder()
                         .addTouchable(Rectangle.newBuilder().addElements(element))
                         .addTouchable(Rectangle.newBuilder().addElements(
-                                SelectorProto.newBuilder().addSelectors("#touch_area_four")))
+                                SelectorProto.newBuilder().addFilters(
+                                        SelectorProto.Filter.newBuilder().setCssSelector(
+                                                "#touch_area_four"))))
                         .build();
         list.add((ActionProto) ActionProto.newBuilder()
                          .setFocusElement(FocusElementProto.newBuilder()
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantBottomsheetTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantBottomsheetTest.java
index 0605261..7b2c204 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantBottomsheetTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantBottomsheetTest.java
@@ -139,7 +139,9 @@
         // Focus on the bottom element.
         list.add((ActionProto) ActionProto.newBuilder()
                          .setFocusElement(FocusElementProto.newBuilder().setElement(
-                                 SelectorProto.newBuilder().addSelectors("p.bottom")))
+                                 SelectorProto.newBuilder().addFilters(
+                                         SelectorProto.Filter.newBuilder().setCssSelector(
+                                                 "p.bottom"))))
                          .build());
         if (withDetails) {
             // ShowDetails.
@@ -416,7 +418,9 @@
         // Focus on the bottom element.
         list.add((ActionProto) ActionProto.newBuilder()
                          .setFocusElement(FocusElementProto.newBuilder().setElement(
-                                 SelectorProto.newBuilder().addSelectors("p.bottom")))
+                                 SelectorProto.newBuilder().addFilters(
+                                         SelectorProto.Filter.newBuilder().setCssSelector(
+                                                 "p.bottom"))))
                          .build());
         // Set handle and header peek mode and auto collapse to that state.
         list.add((ActionProto) ActionProto.newBuilder()
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java
index 3cb8de2..3554e0b 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java
@@ -324,7 +324,10 @@
                 mTestRule.getActivity().getActivityTab(), getURL(TEST_PAGE_B));
 
         SelectorProto element =
-                (SelectorProto) SelectorProto.newBuilder().addSelectors("#profile_name").build();
+                (SelectorProto) SelectorProto.newBuilder()
+                        .addFilters(
+                                SelectorProto.Filter.newBuilder().setCssSelector("#profile_name"))
+                        .build();
 
         ArrayList<ActionProto> list = new ArrayList<>();
         list.add(
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataIntegrationTest.java
index 526dc1e14..e76b3f7 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataIntegrationTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataIntegrationTest.java
@@ -88,7 +88,6 @@
 import org.chromium.chrome.browser.autofill_assistant.proto.UseCreditCardProto.RequiredField;
 import org.chromium.chrome.browser.autofill_assistant.proto.UserFormSectionProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ValueProto;
-import org.chromium.chrome.browser.autofill_assistant.proto.VisibilityRequirement;
 import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule;
 import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -157,24 +156,30 @@
         RequiredField fallbackTextField =
                 (RequiredField) RequiredField.newBuilder()
                         .setValueExpression("57")
-                        .setElement(SelectorProto.newBuilder().addSelectors("#fallback_entry"))
+                        .setElement(SelectorProto.newBuilder().addFilters(
+                                SelectorProto.Filter.newBuilder().setCssSelector(
+                                        "#fallback_entry")))
                         .setFillStrategy(KeyboardValueFillStrategy.SIMULATE_KEY_PRESSES)
                         .build();
         RequiredField fallbackJsDropdownField =
                 (RequiredField) RequiredField.newBuilder()
                         .setValueExpression("55")
-                        .setElement(SelectorProto.newBuilder().addSelectors("#js_dropdown_value"))
-                        .setOptionElementToClick(
-                                SelectorProto.newBuilder().addSelectors("#js_dropdown_options li"))
+                        .setElement(SelectorProto.newBuilder().addFilters(
+                                SelectorProto.Filter.newBuilder().setCssSelector(
+                                        "#js_dropdown_value")))
+                        .setOptionElementToClick(SelectorProto.newBuilder().addFilters(
+                                SelectorProto.Filter.newBuilder().setCssSelector(
+                                        "#js_dropdown_options li")))
                         .setClickType(ClickType.TAP)
                         .build();
         list.add((ActionProto) ActionProto.newBuilder()
-                         .setUseCard(UseCreditCardProto.newBuilder()
-                                             .setFormFieldElement(
-                                                     SelectorProto.newBuilder().addSelectors(
-                                                             "#card_number"))
-                                             .addRequiredFields(fallbackTextField)
-                                             .addRequiredFields(fallbackJsDropdownField))
+                         .setUseCard(
+                                 UseCreditCardProto.newBuilder()
+                                         .setFormFieldElement(SelectorProto.newBuilder().addFilters(
+                                                 SelectorProto.Filter.newBuilder().setCssSelector(
+                                                         "#card_number")))
+                                         .addRequiredFields(fallbackTextField)
+                                         .addRequiredFields(fallbackJsDropdownField))
                          .build());
         list.add((ActionProto) ActionProto.newBuilder()
                          .setPrompt(PromptProto.newBuilder().setMessage("Prompt").addChoices(
@@ -223,18 +228,20 @@
         mHelper.addDummyCreditCard(profileId);
 
         ArrayList<ActionProto> list = new ArrayList<>();
-        list.add((ActionProto) ActionProto.newBuilder()
-                         .setFocusElement(
-                                 FocusElementProto.newBuilder()
-                                         .setElement(SelectorProto.newBuilder().addSelectors(
-                                                 "div.terms"))
-                                         .setTouchableElementArea(
-                                                 ElementAreaProto.newBuilder().addTouchable(
-                                                         Rectangle.newBuilder().addElements(
-                                                                 SelectorProto.newBuilder()
-                                                                         .addSelectors(
-                                                                                 "div.terms")))))
-                         .build());
+        list.add(
+                (ActionProto) ActionProto.newBuilder()
+                        .setFocusElement(
+                                FocusElementProto.newBuilder()
+                                        .setElement(SelectorProto.newBuilder().addFilters(
+                                                SelectorProto.Filter.newBuilder().setCssSelector(
+                                                        "div.terms")))
+                                        .setTouchableElementArea(ElementAreaProto.newBuilder().addTouchable(
+                                                Rectangle.newBuilder().addElements(
+                                                        SelectorProto.newBuilder().addFilters(
+                                                                SelectorProto.Filter.newBuilder()
+                                                                        .setCssSelector(
+                                                                                "div.terms"))))))
+                        .build());
         list.add(
                 (ActionProto) ActionProto.newBuilder()
                         .setCollectUserData(CollectUserDataProto.newBuilder()
@@ -253,9 +260,13 @@
                         .setChip(ChipProto.newBuilder().setText("Toggle"))
                         .setShowOnlyWhen(ElementConditionProto.newBuilder().setMatch(
                                 SelectorProto.newBuilder()
-                                        .addSelectors("div#toggle_on")
-                                        .setVisibilityRequirement(
-                                                VisibilityRequirement.MUST_BE_VISIBLE)))
+                                        .addFilters(
+                                                SelectorProto.Filter.newBuilder().setCssSelector(
+                                                        "div#toggle_on"))
+                                        .addFilters(
+                                                SelectorProto.Filter.newBuilder().setBoundingBox(
+                                                        SelectorProto.EmptyFilter
+                                                                .getDefaultInstance()))))
                         .build();
         list.add((ActionProto) ActionProto.newBuilder()
                          .setPrompt(PromptProto.newBuilder()
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java
index fcacafa..b2fe71ce 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java
@@ -36,9 +36,11 @@
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.hasTypefaceSpan;
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.isImportantForAccessibility;
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.startAutofillAssistant;
+import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewAssertionTrue;
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition;
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.withMinimumSize;
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.withTextGravity;
+import static org.chromium.content_public.browser.test.util.CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL;
 
 import android.graphics.Typeface;
 import android.support.test.InstrumentationRegistry;
@@ -66,11 +68,13 @@
 import org.chromium.chrome.browser.autofill_assistant.proto.CallbackProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ChipProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ChipType;
+import org.chromium.chrome.browser.autofill_assistant.proto.ClearViewContainerProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ClientDimensionProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.CollectUserDataProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.CollectUserDataResultProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ColorProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ComputeValueProto;
+import org.chromium.chrome.browser.autofill_assistant.proto.CreateNestedGenericUiProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.DateFormatProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.DateList;
 import org.chromium.chrome.browser.autofill_assistant.proto.DateProto;
@@ -2487,4 +2491,103 @@
                 .check(matches(withTextGravity(Gravity.START | Gravity.TOP)));
         onView(withText("center-aligned text")).check(matches(withTextGravity(Gravity.CENTER)));
     }
+
+    private ViewProto createSimpleTextView(String identifier, String text) {
+        return (ViewProto) ViewProto.newBuilder()
+                .setIdentifier(identifier)
+                .setTextView(TextViewProto.newBuilder().setText(text))
+                .build();
+    }
+
+    /**
+     * Creates and deletes nested UIs.
+     */
+    @Test
+    @MediumTest
+    public void testCreateNestedUi() {
+        GenericUserInterfaceProto nestedUi =
+                (GenericUserInterfaceProto) GenericUserInterfaceProto.newBuilder()
+                        .setRootView(createSimpleTextView(
+                                /*identifier = */ "nested_text_view", /*text = */ "nested view"))
+                        .build();
+
+        List<InteractionProto> interactions = new ArrayList<>();
+        interactions.add((InteractionProto) InteractionProto.newBuilder()
+                                 .setTriggerEvent(EventProto.newBuilder().setOnViewClicked(
+                                         OnViewClickedEventProto.newBuilder().setViewIdentifier(
+                                                 "text_view_create_nested_on_click")))
+                                 .addCallbacks(CallbackProto.newBuilder().setCreateNestedUi(
+                                         CreateNestedGenericUiProto.newBuilder()
+                                                 .setGenericUiIdentifier("nested_ui_identifier")
+                                                 .setGenericUi(nestedUi)
+                                                 .setParentViewIdentifier("nested_ui_container")))
+                                 .build());
+        interactions.add((InteractionProto) InteractionProto.newBuilder()
+                                 .setTriggerEvent(EventProto.newBuilder().setOnViewClicked(
+                                         OnViewClickedEventProto.newBuilder().setViewIdentifier(
+                                                 "text_view_delete_nested_on_click")))
+                                 .addCallbacks(CallbackProto.newBuilder().setClearViewContainer(
+                                         ClearViewContainerProto.newBuilder().setViewIdentifier(
+                                                 "nested_ui_container")))
+                                 .build());
+
+        ViewProto nestedUiContainer =
+                (ViewProto) ViewProto.newBuilder()
+                        .setIdentifier("nested_ui_container")
+                        .setViewContainer(ViewContainerProto.newBuilder().setLinearLayout(
+                                LinearLayoutProto.newBuilder().setOrientation(
+                                        LinearLayoutProto.Orientation.VERTICAL)))
+                        .build();
+        ViewProto rootView =
+                (ViewProto) ViewProto.newBuilder()
+                        .setViewContainer(
+                                ViewContainerProto.newBuilder()
+                                        .setLinearLayout(
+                                                LinearLayoutProto.newBuilder().setOrientation(
+                                                        LinearLayoutProto.Orientation.VERTICAL))
+                                        .addViews(createSimpleTextView(/*identifier = */
+                                                "text_view_create_nested_on_click",
+                                                /*text = */ "click me to create nested UI"))
+                                        .addViews(createSimpleTextView(/*identifier = */
+                                                "text_view_delete_nested_on_click",
+                                                /*text = */ "click me to delete nested UI"))
+                                        .addViews(nestedUiContainer))
+                        .build();
+
+        GenericUserInterfaceProto genericUserInterface =
+                (GenericUserInterfaceProto) GenericUserInterfaceProto.newBuilder()
+                        .setRootView(rootView)
+                        .setInteractions(
+                                InteractionsProto.newBuilder().addAllInteractions(interactions))
+                        .build();
+
+        ArrayList<ActionProto> list = new ArrayList<>();
+        list.add((ActionProto) ActionProto.newBuilder()
+                         .setShowGenericUi(ShowGenericUiProto.newBuilder().setGenericUserInterface(
+                                 genericUserInterface))
+                         .build());
+        AutofillAssistantTestScript script = new AutofillAssistantTestScript(
+                (SupportedScriptProto) SupportedScriptProto.newBuilder()
+                        .setPath("autofill_assistant_target_website.html")
+                        .setPresentation(PresentationProto.newBuilder().setAutostart(true).setChip(
+                                ChipProto.newBuilder().setText("Autostart")))
+                        .build(),
+                list);
+
+        AutofillAssistantTestService testService =
+                new AutofillAssistantTestService(Collections.singletonList(script));
+        startAutofillAssistant(mTestRule.getActivity(), testService);
+
+        // Create/delete UI multiple times, to ensure that everything is cleaned up properly.
+        for (int i = 0; i < 2; ++i) {
+            waitUntilViewMatchesCondition(
+                    withText("click me to create nested UI"), isCompletelyDisplayed());
+            onView(withText("click me to create nested UI")).perform(click());
+
+            waitUntilViewMatchesCondition(withText("nested view"), isCompletelyDisplayed());
+            onView(withText("click me to delete nested UI")).perform(click());
+            waitUntilViewAssertionTrue(
+                    withText("nested view"), doesNotExist(), DEFAULT_MAX_TIME_TO_POLL);
+        }
+    }
 }
\ No newline at end of file
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantKeyboardIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantKeyboardIntegrationTest.java
index cca69991..40d9024 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantKeyboardIntegrationTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantKeyboardIntegrationTest.java
@@ -104,7 +104,10 @@
     @MediumTest
     public void keyboardDoesNotShowOnElementClick() throws Exception {
         SelectorProto element =
-                (SelectorProto) SelectorProto.newBuilder().addSelectors("#profile_name").build();
+                (SelectorProto) SelectorProto.newBuilder()
+                        .addFilters(
+                                SelectorProto.Filter.newBuilder().setCssSelector("#profile_name"))
+                        .build();
 
         ArrayList<ActionProto> list = new ArrayList<>();
         list.add((ActionProto) ActionProto.newBuilder()
@@ -159,7 +162,10 @@
     @MediumTest
     public void keyboardDoesNotShowOnKeyStrokes() throws Exception {
         SelectorProto element =
-                (SelectorProto) SelectorProto.newBuilder().addSelectors("#profile_name").build();
+                (SelectorProto) SelectorProto.newBuilder()
+                        .addFilters(
+                                SelectorProto.Filter.newBuilder().setCssSelector("#profile_name"))
+                        .build();
 
         ArrayList<ActionProto> list = new ArrayList<>();
         list.add((ActionProto) ActionProto.newBuilder()
@@ -239,10 +245,15 @@
     @Test
     @MediumTest
     public void keyboardDoesNotShowOnElementClickInIFrame() throws Exception {
-        SelectorProto element = (SelectorProto) SelectorProto.newBuilder()
-                                        .addSelectors("#iframe")
-                                        .addSelectors("#name")
-                                        .build();
+        SelectorProto element =
+                (SelectorProto) SelectorProto.newBuilder()
+                        .addFilters(SelectorProto.Filter.newBuilder().setCssSelector("#iframe"))
+                        .addFilters(SelectorProto.Filter.newBuilder().setPickOne(
+                                SelectorProto.EmptyFilter.getDefaultInstance()))
+                        .addFilters(SelectorProto.Filter.newBuilder().setEnterFrame(
+                                SelectorProto.EmptyFilter.getDefaultInstance()))
+                        .addFilters(SelectorProto.Filter.newBuilder().setCssSelector("#name"))
+                        .build();
 
         ArrayList<ActionProto> list = new ArrayList<>();
         list.add((ActionProto) ActionProto.newBuilder()
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayIntegrationTest.java
index 62937c00..f790a45 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayIntegrationTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayIntegrationTest.java
@@ -75,7 +75,10 @@
     @MediumTest
     public void testShowCastOnDocumentElement() throws Exception {
         SelectorProto element =
-                (SelectorProto) SelectorProto.newBuilder().addSelectors("#touch_area_one").build();
+                (SelectorProto) SelectorProto.newBuilder()
+                        .addFilters(
+                                SelectorProto.Filter.newBuilder().setCssSelector("#touch_area_one"))
+                        .build();
 
         ArrayList<ActionProto> list = new ArrayList<>();
         list.add(
@@ -120,7 +123,10 @@
     @MediumTest
     public void testShowCastOnDocumentElementInScrolledBrowserWindow() throws Exception {
         SelectorProto element =
-                (SelectorProto) SelectorProto.newBuilder().addSelectors("#touch_area_five").build();
+                (SelectorProto) SelectorProto.newBuilder()
+                        .addFilters(SelectorProto.Filter.newBuilder().setCssSelector(
+                                "#touch_area_five"))
+                        .build();
 
         ArrayList<ActionProto> list = new ArrayList<>();
         list.add(
@@ -165,10 +171,17 @@
     @Test
     @MediumTest
     public void testShowCastOnIFrameElement() throws Exception {
-        SelectorProto element = (SelectorProto) SelectorProto.newBuilder()
-                                        .addSelectors("#iframe")
-                                        .addSelectors("#touch_area_1")
-                                        .build();
+        SelectorProto element =
+                (SelectorProto) SelectorProto.newBuilder()
+                        .addFilters(SelectorProto.Filter.newBuilder().setCssSelector("#iframe"))
+                        .addFilters(SelectorProto.Filter.newBuilder().setPickOne(
+                                SelectorProto.EmptyFilter.getDefaultInstance()))
+                        .addFilters(SelectorProto.Filter.newBuilder().setEnterFrame(
+                                SelectorProto.EmptyFilter.getDefaultInstance()))
+
+                        .addFilters(
+                                SelectorProto.Filter.newBuilder().setCssSelector("#touch_area_1"))
+                        .build();
 
         ArrayList<ActionProto> list = new ArrayList<>();
         list.add(
@@ -214,10 +227,17 @@
     @Test
     @MediumTest
     public void testShowCastOnIFrameElementInScrollIFrame() throws Exception {
-        SelectorProto element = (SelectorProto) SelectorProto.newBuilder()
-                                        .addSelectors("#iframe")
-                                        .addSelectors("#touch_area_3")
-                                        .build();
+        SelectorProto element =
+                (SelectorProto) SelectorProto.newBuilder()
+                        .addFilters(SelectorProto.Filter.newBuilder().setCssSelector("#iframe"))
+                        .addFilters(SelectorProto.Filter.newBuilder().setPickOne(
+                                SelectorProto.EmptyFilter.getDefaultInstance()))
+                        .addFilters(SelectorProto.Filter.newBuilder().setEnterFrame(
+                                SelectorProto.EmptyFilter.getDefaultInstance()))
+
+                        .addFilters(
+                                SelectorProto.Filter.newBuilder().setCssSelector("#touch_area_3"))
+                        .build();
 
         ArrayList<ActionProto> list = new ArrayList<>();
         list.add(
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPasswordManagerIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPasswordManagerIntegrationTest.java
index 2c207da..234a0b8 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPasswordManagerIntegrationTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPasswordManagerIntegrationTest.java
@@ -106,8 +106,9 @@
                                  SetFormFieldValueProto.newBuilder()
                                          .addValue(SetFormFieldValueProto.KeyPress.newBuilder()
                                                            .setUseUsername(true))
-                                         .setElement(SelectorProto.newBuilder().addSelectors(
-                                                 "#username")))
+                                         .setElement(SelectorProto.newBuilder().addFilters(
+                                                 SelectorProto.Filter.newBuilder().setCssSelector(
+                                                         "#username"))))
                          .build());
         // TODO(crbug.com/1057608): Implement Android wrapper for PasswordStore to add a
         // step and
@@ -116,8 +117,9 @@
                          .setGeneratePasswordForFormField(
                                  GeneratePasswordForFormFieldProto.newBuilder()
                                          .setMemoryKey("memory-key")
-                                         .setElement(SelectorProto.newBuilder().addSelectors(
-                                                 "#new-password")))
+                                         .setElement(SelectorProto.newBuilder().addFilters(
+                                                 SelectorProto.Filter.newBuilder().setCssSelector(
+                                                         "#new-password"))))
                          .build());
 
         list.add((ActionProto) ActionProto.newBuilder()
@@ -125,16 +127,18 @@
                                  SetFormFieldValueProto.newBuilder()
                                          .addValue(SetFormFieldValueProto.KeyPress.newBuilder()
                                                            .setClientMemoryKey("memory-key"))
-                                         .setElement(SelectorProto.newBuilder().addSelectors(
-                                                 "#new-password")))
+                                         .setElement(SelectorProto.newBuilder().addFilters(
+                                                 SelectorProto.Filter.newBuilder().setCssSelector(
+                                                         "#new-password"))))
                          .build());
         list.add((ActionProto) ActionProto.newBuilder()
                          .setSetFormValue(
                                  SetFormFieldValueProto.newBuilder()
                                          .addValue(SetFormFieldValueProto.KeyPress.newBuilder()
                                                            .setClientMemoryKey("memory-key"))
-                                         .setElement(SelectorProto.newBuilder().addSelectors(
-                                                 "#password-conf")))
+                                         .setElement(SelectorProto.newBuilder().addFilters(
+                                                 SelectorProto.Filter.newBuilder().setCssSelector(
+                                                         "#password-conf"))))
                          .build());
 
         list.add((ActionProto) ActionProto.newBuilder()
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
index 520fcf28..bdbdac76 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
@@ -117,27 +117,31 @@
                                                                    .setRequestPayerPhone(false))
                                         .setRequestTermsAndConditions(false))
                         .build());
-        list.add((ActionProto) ActionProto.newBuilder()
-                         .setUseAddress(
-                                 UseAddressProto.newBuilder()
-                                         .setName("contact")
-                                         .setFormFieldElement(
-                                                 SelectorProto.newBuilder().addSelectors(
-                                                         "#profile_name"))
-                                         .addRequiredFields(
-                                                 RequiredField.newBuilder()
-                                                         .setValueExpression("7")
-                                                         .setElement(
-                                                                 SelectorProto.newBuilder()
-                                                                         .addSelectors(
-                                                                                 "#profile_name")))
-                                         .addRequiredFields(
-                                                 RequiredField.newBuilder()
-                                                         .setValueExpression("9")
-                                                         .setElement(
-                                                                 SelectorProto.newBuilder()
-                                                                         .addSelectors("#email"))))
-                         .build());
+        list.add(
+                (ActionProto) ActionProto.newBuilder()
+                        .setUseAddress(
+                                UseAddressProto.newBuilder()
+                                        .setName("contact")
+                                        .setFormFieldElement(SelectorProto.newBuilder().addFilters(
+                                                SelectorProto.Filter.newBuilder().setCssSelector(
+                                                        "#profile_name")))
+                                        .addRequiredFields(
+                                                RequiredField.newBuilder()
+                                                        .setValueExpression("7")
+                                                        .setElement(SelectorProto.newBuilder().addFilters(
+                                                                SelectorProto.Filter.newBuilder()
+                                                                        .setCssSelector(
+                                                                                "#profile_name"))))
+                                        .addRequiredFields(
+                                                RequiredField.newBuilder()
+                                                        .setValueExpression("9")
+                                                        .setElement(
+                                                                SelectorProto.newBuilder().addFilters(
+                                                                        SelectorProto.Filter
+                                                                                .newBuilder()
+                                                                                .setCssSelector(
+                                                                                        "#email")))))
+                        .build());
         list.add((ActionProto) ActionProto.newBuilder()
                          .setPrompt(PromptProto.newBuilder().setMessage("Prompt").addChoices(
                                  PromptProto.Choice.newBuilder()))
@@ -265,7 +269,9 @@
                 (ActionProto) ActionProto.newBuilder()
                         .setUseAddress(
                                 UseAddressProto.newBuilder().setName("contact").setFormFieldElement(
-                                        SelectorProto.newBuilder().addSelectors("#profile_name")))
+                                        SelectorProto.newBuilder().addFilters(
+                                                SelectorProto.Filter.newBuilder().setCssSelector(
+                                                        "#profile_name"))))
                         .build());
         list.add((ActionProto) ActionProto.newBuilder()
                          .setPrompt(PromptProto.newBuilder().setMessage("Prompt").addChoices(
@@ -318,7 +324,9 @@
                 (ActionProto) ActionProto.newBuilder()
                         .setUseAddress(
                                 UseAddressProto.newBuilder().setName("contact").setFormFieldElement(
-                                        SelectorProto.newBuilder().addSelectors("#profile_name")))
+                                        SelectorProto.newBuilder().addFilters(
+                                                SelectorProto.Filter.newBuilder().setCssSelector(
+                                                        "#profile_name"))))
                         .build());
         list.add((ActionProto) ActionProto.newBuilder()
                          .setPrompt(PromptProto.newBuilder().setMessage("Prompt").addChoices(
@@ -420,7 +428,9 @@
                 (ActionProto) ActionProto.newBuilder()
                         .setUseAddress(
                                 UseAddressProto.newBuilder().setName("contact").setFormFieldElement(
-                                        SelectorProto.newBuilder().addSelectors("#profile_name")))
+                                        SelectorProto.newBuilder().addFilters(
+                                                SelectorProto.Filter.newBuilder().setCssSelector(
+                                                        "#profile_name"))))
                         .build());
         list.add((ActionProto) ActionProto.newBuilder()
                          .setPrompt(PromptProto.newBuilder().setMessage("Prompt").addChoices(
@@ -491,11 +501,12 @@
                                                      .setRequestTermsAndConditions(false))
                          .build());
         list.add((ActionProto) ActionProto.newBuilder()
-                         .setUseCard(org.chromium.chrome.browser.autofill_assistant.proto
-                                             .UseCreditCardProto.newBuilder()
-                                             .setFormFieldElement(
-                                                     SelectorProto.newBuilder().addSelectors(
-                                                             "#card_number")))
+                         .setUseCard(
+                                 org.chromium.chrome.browser.autofill_assistant.proto
+                                         .UseCreditCardProto.newBuilder()
+                                         .setFormFieldElement(SelectorProto.newBuilder().addFilters(
+                                                 SelectorProto.Filter.newBuilder().setCssSelector(
+                                                         "#card_number"))))
                          .build());
         list.add((ActionProto) ActionProto.newBuilder()
                          .setPrompt(PromptProto.newBuilder().setMessage("Prompt").addChoices(
diff --git a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_option_toggle.xml b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_option_toggle.xml
index 40886fc..5521218b 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_option_toggle.xml
+++ b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_option_toggle.xml
@@ -10,7 +10,8 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:paddingStart="@dimen/keyboard_accessory_suggestion_padding"
-    android:paddingEnd="@dimen/keyboard_accessory_suggestion_padding"
+    android:paddingEnd="6dp"
+    android:layout_marginTop="8dp"
     android:fillViewport="true"
     android:minHeight="@dimen/keyboard_accessory_suggestion_height"
     android:background="?attr/selectableItemBackground">
@@ -32,11 +33,12 @@
             android:id="@+id/option_toggle_subtitle"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:textAppearance="@style/TextAppearance.TextLarge.Secondary" />
+            android:textAppearance="@style/TextAppearance.TextMedium.Secondary" />
     </LinearLayout>
 
     <android.widget.Switch
         android:id="@+id/option_toggle_switch"
+        android:layout_marginStart="16dp"
         android:layout_width="48dp"
         android:layout_height="wrap_content"
         android:layout_weight="0"
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java
index 0f9008d..14d7b5b 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.tasks.tab_management;
 
+import android.os.Build.VERSION_CODES;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.view.ViewGroup;
@@ -20,6 +21,7 @@
 import org.chromium.base.GarbageCollectionTestUtils;
 import org.chromium.base.SysUtils;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Restriction;
@@ -287,7 +289,11 @@
 
     @Test
     @MediumTest
+    // clang-format off
+    @DisableIf.Build(sdk_is_greater_than = VERSION_CODES.O_MR1, supported_abis_includes = "x86",
+        message = "https://crbug.com/1075548")
     public void testShowTabsWithPreSelectedTabs_10Tabs() {
+        // clang-format on
         prepareBlankTab(11, false);
         int preSelectedTabCount = 10;
         List<Tab> tabs = getTabsInCurrentTabModel();
diff --git a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrDelegateFallback.java b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrDelegateFallback.java
index 35a904fa..42991b6 100644
--- a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrDelegateFallback.java
+++ b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrDelegateFallback.java
@@ -16,7 +16,6 @@
 import org.chromium.base.Log;
 import org.chromium.base.compat.ApiHelperForN;
 import org.chromium.base.library_loader.LibraryLoader;
-import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.task.PostTask;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
@@ -29,9 +28,6 @@
  * Fallback {@link VrDelegate} implementation if the VR module is not available.
  */
 /* package */ class VrDelegateFallback extends VrDelegate {
-    /* package */ static void recordEnterVrBrowserWithoutFeatureModule(boolean sample) {
-        RecordHistogram.recordBooleanHistogram("VR.EnterVrBrowserWithoutFeatureModule", sample);
-    }
     private static final String TAG = "VrDelegateFallback";
     private static final boolean DEBUG_LOGS = false;
     private static final String DEFAULT_VR_MODE_PACKAGE = "com.google.vr.vrcore";
@@ -199,8 +195,6 @@
         }
         assert VrModule.isInstalled();
 
-        recordEnterVrBrowserWithoutFeatureModule(true);
-
         // We need native to enter VR. Enter VR flow will automatically continue once native is
         // loaded.
         if (!LibraryLoader.getInstance().isInitialized()) return;
@@ -214,8 +208,6 @@
     }
 
     private void onVrModuleInstallFailure(Activity activity) {
-        recordEnterVrBrowserWithoutFeatureModule(false);
-
         // For SVR close Chrome. For standalones launch into 2D-in-VR (if that fails, close Chrome).
         if (bootsToVr()) {
             if (!setVrMode(activity, false)) {
diff --git a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrIntentDelegateFallback.java b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrIntentDelegateFallback.java
index 922523b2..993b09a4 100644
--- a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrIntentDelegateFallback.java
+++ b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrIntentDelegateFallback.java
@@ -13,7 +13,6 @@
 public class VrIntentDelegateFallback extends VrIntentDelegate {
     @Override
     public Intent setupVrFreIntent(Context context, Intent freIntent) {
-        VrDelegateFallback.recordEnterVrBrowserWithoutFeatureModule(false);
         if (VrModuleProvider.getDelegate().bootsToVr()) return freIntent;
         // Don't bother handling FRE without VR module on smartphone VR. Just request module and
         // return to caller.
diff --git a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
index c1f6ed81..ba75dc9 100644
--- a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
+++ b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
@@ -1048,18 +1048,12 @@
         if (showExitPromptBeforeDoff) {
             VrShellJni.get().requestToExitVr(mNativeVrShell, VrShell.this, reason);
         } else {
-            VrShellJni.get().logUnsupportedModeUserMetric(mNativeVrShell, VrShell.this, reason);
             mDelegate.onExitVrRequestResult(true);
         }
     }
 
     @CalledByNative
-    private void onExitVrRequestResult(@UiUnsupportedMode int reason, boolean shouldExit) {
-        if (shouldExit) {
-            if (mNativeVrShell != 0) {
-                VrShellJni.get().logUnsupportedModeUserMetric(mNativeVrShell, VrShell.this, reason);
-            }
-        }
+    private void onExitVrRequestResult(boolean shouldExit) {
         mDelegate.onExitVrRequestResult(shouldExit);
     }
 
@@ -1381,8 +1375,6 @@
         void setHistoryButtonsEnabled(
                 long nativeVrShell, VrShell caller, boolean canGoBack, boolean canGoForward);
         void requestToExitVr(long nativeVrShell, VrShell caller, @UiUnsupportedMode int reason);
-        void logUnsupportedModeUserMetric(
-                long nativeVrShell, VrShell caller, @UiUnsupportedMode int mode);
         void showSoftInput(long nativeVrShell, VrShell caller, boolean show);
         void updateWebInputIndices(long nativeVrShell, VrShell caller, int selectionStart,
                 int selectionEnd, int compositionStart, int compositionEnd);
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/testing/conformance/storage/ContentStorageConformanceTest.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/testing/conformance/storage/ContentStorageConformanceTest.java
index 07e83f2..5401664 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/testing/conformance/storage/ContentStorageConformanceTest.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/testing/conformance/storage/ContentStorageConformanceTest.java
@@ -6,10 +6,13 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.os.Build;
+
 import org.junit.Before;
 import org.junit.Test;
 
 import org.chromium.base.Consumer;
+import org.chromium.base.test.util.DisableIf;
 import org.chromium.chrome.browser.feed.library.api.host.storage.CommitResult;
 import org.chromium.chrome.browser.feed.library.api.host.storage.ContentMutation;
 import org.chromium.chrome.browser.feed.library.api.host.storage.ContentStorage;
@@ -26,7 +29,11 @@
  * Conformance test for {@link ContentStorage}. Hosts who wish to test against this should extend
  * this class and set {@code storage} to the Host implementation.
  */
+// clang-format off
+@DisableIf.Build(sdk_is_greater_than = Build.VERSION_CODES.N_MR1,
+    sdk_is_less_than = Build.VERSION_CODES.P, message = "https://crbug.com/1091301")
 public abstract class ContentStorageConformanceTest {
+    //clang-format on
     private static final String KEY = "key";
     private static final String KEY_0 = KEY + " 0";
     private static final String KEY_1 = KEY + " 1";
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/testing/conformance/storage/JournalStorageConformanceTest.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/testing/conformance/storage/JournalStorageConformanceTest.java
index 1871325..41bd5f7 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/testing/conformance/storage/JournalStorageConformanceTest.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/testing/conformance/storage/JournalStorageConformanceTest.java
@@ -6,11 +6,14 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.os.Build;
+
 import com.google.protobuf.InvalidProtocolBufferException;
 
 import org.junit.Test;
 
 import org.chromium.base.Consumer;
+import org.chromium.base.test.util.DisableIf;
 import org.chromium.chrome.browser.feed.library.api.host.storage.CommitResult;
 import org.chromium.chrome.browser.feed.library.api.host.storage.JournalMutation;
 import org.chromium.chrome.browser.feed.library.api.host.storage.JournalStorage;
@@ -26,7 +29,11 @@
  * Conformance test for {@link JournalStorage}. Hosts who wish to test against this should extend
  * this class and set {@code storage} to the Host implementation.
  */
+// clang-format off
+@DisableIf.Build(sdk_is_greater_than = Build.VERSION_CODES.N_MR1,
+    sdk_is_less_than = Build.VERSION_CODES.P, message = "https://crbug.com/1091301")
 public abstract class JournalStorageConformanceTest {
+    //clank-format on
     private static final String JOURNAL_NAME = "journal name";
     private static final String JOURNAL_COPY_NAME = "journal copy name";
     private static final byte[] DATA_0 = "data 0".getBytes(Charset.forName("UTF-8"));
diff --git a/chrome/android/java/res/layout/omnibox_query_tiles_suggestion.xml b/chrome/android/java/res/layout/omnibox_query_tiles_suggestion.xml
index 683dcbc..49e2adf4 100644
--- a/chrome/android/java/res/layout/omnibox_query_tiles_suggestion.xml
+++ b/chrome/android/java/res/layout/omnibox_query_tiles_suggestion.xml
@@ -8,5 +8,5 @@
     android:id="@+id/omnibox_query_tiles"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:padding="@dimen/card_padding">
+    android:padding="12dp">
 </FrameLayout>
diff --git a/chrome/android/java/res/layout/start_top_toolbar.xml b/chrome/android/java/res/layout/start_top_toolbar.xml
index 5954f6a..479e87a 100644
--- a/chrome/android/java/res/layout/start_top_toolbar.xml
+++ b/chrome/android/java/res/layout/start_top_toolbar.xml
@@ -31,8 +31,6 @@
         android:layout_height="32dp"
         android:layout_centerHorizontal="true"
         android:layout_centerVertical="true"
-        android:paddingStart="8dp"
-        android:paddingEnd="8dp"
         android:scaleType="centerInside"
         android:adjustViewBounds="true"
         app:srcCompat="@drawable/google_logo"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
index 9c96cdd..42b4500 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
@@ -187,17 +187,6 @@
     public static final String EXTRA_INCOGNITO_MODE = "org.chromium.chrome.browser.incognito_mode";
 
     /**
-     * Byte array for the POST data when load a url, only Intents sent by Chrome can use this.
-     */
-    public static final String EXTRA_POST_DATA = "com.android.chrome.post_data";
-
-    /**
-     * The type of the POST data, need to be added to the HTTP request header, only Intents sent by
-     * Chrome can use this.
-     */
-    public static final String EXTRA_POST_DATA_TYPE = "com.android.chrome.post_data_type";
-
-    /**
      * Fake ComponentName used in constructing TRUSTED_APPLICATION_CODE_EXTRA.
      */
     private static ComponentName sFakeComponentName;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/permissiondelegation/InstalledWebappBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/permissiondelegation/InstalledWebappBridge.java
index 2495e81d..6f534f9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/permissiondelegation/InstalledWebappBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/permissiondelegation/InstalledWebappBridge.java
@@ -82,7 +82,9 @@
         TrustedWebActivityPermissionManager manager = TrustedWebActivityPermissionManager.get();
         Origin origin = Origin.create(Uri.parse(url));
         String packageName = manager.getDelegatePackageName(origin);
-        return manager.isRunningTwa() && manager.hasAndroidLocationPermission(packageName) != null;
+        return manager.isRunningTwa()
+                && TrustedWebActivityPermissionManager.hasAndroidLocationPermission(packageName)
+                != null;
     }
 
     @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/permissiondelegation/TrustedWebActivityPermissionManager.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/permissiondelegation/TrustedWebActivityPermissionManager.java
index 708c5dc9..d43d12a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/permissiondelegation/TrustedWebActivityPermissionManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/permissiondelegation/TrustedWebActivityPermissionManager.java
@@ -240,7 +240,7 @@
      * {@code null} if it does not exist or did not request location permission.
      **/
     @Nullable
-    Boolean hasAndroidLocationPermission(String packageName) {
+    public static Boolean hasAndroidLocationPermission(String packageName) {
         try {
             PackageManager pm = ContextUtils.getApplicationContext().getPackageManager();
             PackageInfo packageInfo =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
index 2d608a2..8c132d5f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
@@ -25,6 +25,7 @@
 import org.chromium.chrome.browser.ShortcutHelper;
 import org.chromium.chrome.browser.app.tab_activity_glue.ActivityTabWebContentsDelegateAndroid;
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
+import org.chromium.chrome.browser.browserservices.permissiondelegation.TrustedWebActivityPermissionManager;
 import org.chromium.chrome.browser.browserservices.ui.controller.Verifier;
 import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabCoordinator;
 import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulator;
@@ -326,6 +327,18 @@
         public boolean canShowAppBanners() {
             return mActivityType == ActivityType.CUSTOM_TAB;
         }
+
+        @Override
+        protected boolean isInstalledWebappDelegateGeolocation() {
+            if ((mActivity instanceof CustomTabActivity)
+                    && ((CustomTabActivity) mActivity).isInTwaMode()) {
+                // Whether the corresponding TWA client app enrolled in location delegation.
+                return TrustedWebActivityPermissionManager.hasAndroidLocationPermission(
+                               ((CustomTabActivity) mActivity).getTwaPackage())
+                        != null;
+            }
+            return false;
+        }
     }
 
     private final ChromeActivity<?> mActivity;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/ntp/OWNERS
index a564d5f4..3a83d5c9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/OWNERS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/OWNERS
@@ -1,5 +1,9 @@
 tedchoc@chromium.org
 twellington@chromium.org
 
+# For changes related to the feed.
+per-file *SectionHeader.java=file://chrome/browser/android/feed/OWNERS
+per-file *SectionHeaderView.java=file://chrome/browser/android/feed/OWNERS
+
 # TEAM: ntp-dev@chromium.org
 # COMPONENT: UI>Browser>NewTabPage
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorImpl.java
index e5dcd53..415645a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorImpl.java
@@ -46,7 +46,6 @@
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.modelutil.LazyConstructionPropertyMcp;
 import org.chromium.ui.modelutil.MVCListAdapter;
-import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
 import org.chromium.ui.modelutil.PropertyModel;
 
 import java.util.ArrayList;
@@ -336,11 +335,6 @@
         return mMediator;
     }
 
-    @VisibleForTesting
-    ModelList getSuggestionModelList() {
-        return mMediator.getSuggestionModelList();
-    }
-
     private void onTileSelected(QueryTile queryTile) {
         mMediator.onQueryTileSelected(queryTile);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreviewPlayer.java b/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreviewPlayer.java
index 02cf0c05..3a3feab 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreviewPlayer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreviewPlayer.java
@@ -4,11 +4,17 @@
 
 package org.chromium.chrome.browser.paint_preview;
 
-import org.chromium.base.Callback;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import org.chromium.base.UserData;
 import org.chromium.chrome.browser.paint_preview.services.PaintPreviewTabService;
 import org.chromium.chrome.browser.paint_preview.services.PaintPreviewTabServiceFactory;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabThemeColorHelper;
+import org.chromium.chrome.browser.tab.TabViewManager;
+import org.chromium.chrome.browser.tab.TabViewProvider;
 import org.chromium.components.paintpreview.player.PlayerManager;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.url.GURL;
@@ -17,42 +23,47 @@
  * Responsible for checking for and displaying Paint Previews that are associated with a
  * {@link Tab} by overlaying the content view.
  */
-public class TabbedPaintPreviewPlayer {
+public class TabbedPaintPreviewPlayer implements TabViewProvider, UserData {
+    public static final Class<TabbedPaintPreviewPlayer> USER_DATA_KEY =
+            TabbedPaintPreviewPlayer.class;
+
     private Tab mTab;
     private PaintPreviewTabService mPaintPreviewTabService;
     private PlayerManager mPlayerManager;
-    private Callback<Boolean> mShownCallback;
+    private Runnable mOnShown;
+    private Runnable mOnDismissed;
+
+    public static TabbedPaintPreviewPlayer get(Tab tab) {
+        if (tab.getUserDataHost().getUserData(USER_DATA_KEY) == null) {
+            tab.getUserDataHost().setUserData(USER_DATA_KEY, new TabbedPaintPreviewPlayer(tab));
+        }
+        return tab.getUserDataHost().getUserData(USER_DATA_KEY);
+    }
+
+    private TabbedPaintPreviewPlayer(Tab tab) {
+        mTab = tab;
+        mPaintPreviewTabService = PaintPreviewTabServiceFactory.getServiceInstance();
+    }
 
     /**
      * Shows a Paint Preview for the provided tab if it exists.
-     * @param tab The tab to show.
-     * @param shownCallback returns true once the Paint Preview is shown or false if showing failed.
+     * @param onShown The callback for when the Paint Preview is shown.
+     * @param onDismissed The callback for when the Paint Preview is dismissed.
      * @return a boolean indicating whether a Paint Preview exists for the tab.
      */
-    public boolean showIfExistsForTab(Tab tab, Callback<Boolean> shownCallback) {
-        if (mTab != null) removePaintPreview();
-
-        mTab = tab;
-        if (mPaintPreviewTabService == null) {
-            mPaintPreviewTabService = PaintPreviewTabServiceFactory.getServiceInstance();
-        }
-        mShownCallback = shownCallback;
+    public boolean showIfExists(@Nullable Runnable onShown, @Nullable Runnable onDismissed) {
+        if (isShowing()) return true;
 
         // Check if a capture exists. This is a quick check using a cache.
-        boolean hasCapture = mPaintPreviewTabService.hasCaptureForTab(tab.getId());
+        boolean hasCapture = mPaintPreviewTabService.hasCaptureForTab(mTab.getId());
+        mOnShown = onShown;
+        mOnDismissed = onDismissed;
         if (hasCapture) {
             mPlayerManager = new PlayerManager(mTab.getUrl(), mTab.getContext(),
-                    mPaintPreviewTabService, String.valueOf(mTab.getId()),
-                    TabbedPaintPreviewPlayer.this::onLinkClicked,
-                    TabbedPaintPreviewPlayer.this::onRefresh,
-                    TabbedPaintPreviewPlayer.this::addPlayerView,
-                    TabThemeColorHelper.getBackgroundColor(mTab), () -> {
-                        if (mShownCallback != null) {
-                            mShownCallback.onResult(false);
-                            mShownCallback = null;
-                        }
-                        removePaintPreview();
-                    });
+                    mPaintPreviewTabService, String.valueOf(mTab.getId()), this::onLinkClicked,
+                    this::removePaintPreview,
+                    () -> TabViewManager.get(mTab).addTabViewProvider(this),
+                    TabThemeColorHelper.getBackgroundColor(mTab), this::removePaintPreview);
         }
 
         return hasCapture;
@@ -62,35 +73,50 @@
      * Removes the view containing the Paint Preview from the most recently shown {@link Tab}. Does
      * nothing if there is no view showing.
      */
-    public void removePaintPreview() {
+    private void removePaintPreview() {
         if (mTab == null || mPlayerManager == null) return;
 
-        mTab.getContentView().removeView(mPlayerManager.getView());
+        TabViewManager.get(mTab).removeTabViewProvider(this);
         mPlayerManager.destroy();
         mPlayerManager = null;
-        mTab = null;
+        mOnShown = null;
+        mOnDismissed = null;
     }
 
-    private void addPlayerView() {
-        mTab.getContentView().addView(mPlayerManager.getView());
-
-        if (mShownCallback != null) {
-            mShownCallback.onResult(true);
-            mShownCallback = null;
-        }
+    public boolean isShowing() {
+        return TabViewManager.get(mTab).getCurrentTabViewProvider() == this;
     }
 
     private void onLinkClicked(GURL url) {
         if (mTab == null || !url.isValid() || url.isEmpty()) return;
 
-        mTab.loadUrl(new LoadUrlParams(url.getSpec()));
         removePaintPreview();
+        mTab.loadUrl(new LoadUrlParams(url.getSpec()));
     }
 
-    private void onRefresh() {
-        if (mTab == null) return;
+    @Override
+    public int getTabViewProviderType() {
+        return Type.PAINT_PREVIEW;
+    }
 
-        mTab.reload();
+    @Override
+    public View getView() {
+        return mPlayerManager == null ? null : mPlayerManager.getView();
+    }
+
+    @Override
+    public void onShown() {
+        if (mOnShown != null) mOnShown.run();
+    }
+
+    @Override
+    public void onHidden() {
+        if (mOnDismissed != null) mOnDismissed.run();
+    }
+
+    @Override
+    public void destroy() {
         removePaintPreview();
+        mTab = null;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerMediator.java
index e687d33..78626d6c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerMediator.java
@@ -14,12 +14,11 @@
 import org.chromium.chrome.browser.payments.handler.PaymentHandlerCoordinator.PaymentHandlerUiObserver;
 import org.chromium.chrome.browser.payments.handler.toolbar.PaymentHandlerToolbarCoordinator.PaymentHandlerToolbarObserver;
 import org.chromium.chrome.browser.ui.TabObscuringHandler;
-import org.chromium.chrome.browser.widget.ScrimView;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController.SheetState;
-import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetControllerImpl;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetObserver;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
+import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
 import org.chromium.content_public.browser.NavigationController;
 import org.chromium.content_public.browser.NavigationHandle;
 import org.chromium.content_public.browser.WebContents;
@@ -138,14 +137,10 @@
         ChromeActivity activity = ChromeActivity.fromWebContents(mWebContentsRef);
         assert activity != null;
 
-        // TODO(1002277): Use the proper scrim API when available.
-        BottomSheetControllerImpl controller =
-                (BottomSheetControllerImpl) activity.getBottomSheetController();
-        ScrimView.ScrimParams params =
-                controller.createScrimParams(new ScrimView.EmptyScrimObserver());
-        ScrimView scrim = ChromeActivity.fromWebContents(mWebContentsRef).getScrim();
-        scrim.showScrim(params);
-        scrim.setViewAlpha(0);
+        BottomSheetController controller = activity.getBottomSheetController();
+        PropertyModel params = controller.createScrimParams();
+        ScrimCoordinator coordinator = controller.getScrimCoordinator();
+        coordinator.showScrim(params);
 
         setIsObscuringAllTabs(activity, true);
     }
@@ -180,7 +175,9 @@
         ChromeActivity activity = ChromeActivity.fromWebContents(mWebContentsRef);
         assert activity != null;
 
-        activity.getScrim().hideScrim(true);
+        ScrimCoordinator coordinator = activity.getBottomSheetController().getScrimCoordinator();
+        coordinator.hideScrim(true);
+
         setIsObscuringAllTabs(activity, false);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
index a314b0f..da252b5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
@@ -14,7 +14,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.app.ActivityOptionsCompat;
 
@@ -103,8 +102,6 @@
 
     /** Input submitted before before the native library was loaded. */
     private String mQueuedUrl;
-    private String mQueuedPostDataType;
-    private byte[] mQueuedPostData;
 
     /** The View that represents the search box. */
     private SearchActivityLocationBarLayout mSearchBox;
@@ -276,7 +273,7 @@
         assert !mIsActivityUsable
                 : "finishDeferredInitialization() incorrectly called multiple times";
         mIsActivityUsable = true;
-        if (mQueuedUrl != null) loadUrl(mQueuedUrl, mQueuedPostDataType, mQueuedPostData);
+        if (mQueuedUrl != null) loadUrl(mQueuedUrl);
 
         // TODO(tedchoc): Warmup triggers the CustomTab layout to be inflated, but this widget
         //                will navigate to Tabbed mode.  Investigate whether this can inflate
@@ -330,53 +327,29 @@
     }
 
     @Override
-    public void loadUrl(String url, @Nullable String postDataType, @Nullable byte[] postData) {
+    public void loadUrl(String url) {
         // Wait until native has loaded.
         if (!mIsActivityUsable) {
             mQueuedUrl = url;
-            mQueuedPostDataType = postDataType;
-            mQueuedPostData = postData;
             return;
         }
 
-        Intent intent = createIntentForStartActivity(url, postDataType, postData);
-        if (intent == null) return;
-
-        IntentUtils.safeStartActivity(this, intent,
-                ActivityOptionsCompat
-                        .makeCustomAnimation(this, android.R.anim.fade_in, android.R.anim.fade_out)
-                        .toBundle());
-        RecordUserAction.record("SearchWidget.SearchMade");
-        finish();
-    }
-
-    /**
-     * Creates an intent that will be used to launch Chrome.
-     *
-     * @param url The URL to be loaded.
-     * @param postDataType   postData type.
-     * @param postData       Post-data to include in the tab URL's request body, ex. bitmap when
-     *         image search.
-     * @return the intent will be passed to ChromeLauncherActivity, null if input was emprty.
-     */
-    private Intent createIntentForStartActivity(
-            String url, @Nullable String postDataType, @Nullable byte[] postData) {
         // Don't do anything if the input was empty. This is done after the native check to prevent
         // resending a queued query after the user deleted it.
-        if (TextUtils.isEmpty(url)) return null;
+        if (TextUtils.isEmpty(url)) return;
 
         // Fix up the URL and send it to the full browser.
         GURL fixedUrl = UrlFormatter.fixupUrl(url);
         Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(fixedUrl.getValidSpecOrEmpty()));
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
         intent.setClass(this, ChromeLauncherActivity.class);
-        if (!TextUtils.isEmpty(postDataType) && postData != null && postData.length != 0) {
-            intent.putExtra(IntentHandler.EXTRA_POST_DATA_TYPE, postDataType);
-            intent.putExtra(IntentHandler.EXTRA_POST_DATA, postData);
-        }
         IntentHandler.addTrustedIntentExtras(intent);
-
-        return intent;
+        IntentUtils.safeStartActivity(this, intent,
+                ActivityOptionsCompat
+                        .makeCustomAnimation(this, android.R.anim.fade_in, android.R.anim.fade_out)
+                        .toBundle());
+        RecordUserAction.record("SearchWidget.SearchMade");
+        finish();
     }
 
     private ViewGroup createContentView() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java
index 076bbeb..91d90677 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java
@@ -28,7 +28,7 @@
     /** Delegates calls out to the containing Activity. */
     public static interface Delegate {
         /** Load a URL in the associated tab. */
-        void loadUrl(String url, @Nullable String postDataType, @Nullable byte[] postData);
+        void loadUrl(String url);
 
         /** The user hit the back button. */
         void backKeyPressed();
@@ -56,9 +56,8 @@
     }
 
     @Override
-    public void loadUrlWithPostData(String url, int transition, long inputStart,
-            @Nullable String postDataType, @Nullable byte[] postData) {
-        mDelegate.loadUrl(url, postDataType, postData);
+    public void loadUrl(String url, int transition, long inputStart) {
+        mDelegate.loadUrl(url);
         LocaleManager.getInstance().recordLocaleBasedSearchMetrics(true, url, transition);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java
index bf9fefa..71e40593 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java
@@ -331,13 +331,24 @@
      * and {@link PersonalDataManager}.
      */
     private void updateSyncStateFromSelectedModelTypes() {
-        mProfileSyncService.setChosenDataTypes(
-                mSyncEverything.isChecked(), getSelectedModelTypes());
+        Set<Integer> selectedModelTypes = getSelectedModelTypes();
+        mProfileSyncService.setChosenDataTypes(mSyncEverything.isChecked(), selectedModelTypes);
         // Note: mSyncPaymentsIntegration should be checked if mSyncEverything is checked, but if
         // mSyncEverything was just enabled, then that state may not have propagated to
         // mSyncPaymentsIntegration yet. See crbug.com/972863.
         PersonalDataManager.setPaymentsIntegrationEnabled(mSyncEverything.isChecked()
                 || (mSyncPaymentsIntegration.isChecked() && mSyncAutofill.isChecked()));
+
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)) {
+            boolean atLeastOneDataTypeEnabled =
+                    mSyncEverything.isChecked() || selectedModelTypes.size() > 0;
+            if (mProfileSyncService.isSyncRequested() && !atLeastOneDataTypeEnabled) {
+                mProfileSyncService.requestStop();
+            } else if (!mProfileSyncService.isSyncRequested() && atLeastOneDataTypeEnabled) {
+                mProfileSyncService.requestStart();
+            }
+        }
+
         // Some calls to setChosenDataTypes don't trigger syncStateChanged, so schedule update here.
         PostTask.postTask(UiThreadTaskTraits.DEFAULT, this::updateSyncPreferences);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroidImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroidImpl.java
index 1a6b2b7..7d1d498 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroidImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroidImpl.java
@@ -315,6 +315,17 @@
         return mDelegate.isCustomTab();
     }
 
+    /**
+     * Checks if the associated tab is running an activity for installed webapp (TWA only for now),
+     * and whether the geolocation request should be delegated to the client app.
+     * @return true if this is TWA and should delegate geolocation request.
+     */
+    @CalledByNative
+    @Override
+    protected boolean isInstalledWebappDelegateGeolocation() {
+        return mDelegate.isInstalledWebappDelegateGeolocation();
+    }
+
     @Override
     public int getTopControlsHeight() {
         return mDelegate.getTopControlsHeight();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
index df3928d6..6df0102 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
@@ -33,7 +33,6 @@
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.common.Referrer;
-import org.chromium.content_public.common.ResourceRequestBody;
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.url.GURL;
@@ -299,9 +298,8 @@
      * @param intentTimestamp the time the intent was received.
      * @return the tab the URL was opened in, could be a new tab or a reused one.
      */
-    // TODO(crbug.com/1081924): Clean up the launches from SearchActivity/Chrome.
-    public Tab launchUrlFromExternalApp(String url, String referer, String headers, String appId,
-            boolean forceNewTab, Intent intent, long intentTimestamp) {
+    public Tab launchUrlFromExternalApp(String url, String referer, String headers,
+            String appId, boolean forceNewTab, Intent intent, long intentTimestamp) {
         assert !mIncognito;
         boolean isLaunchedFromChrome = TextUtils.equals(appId, mActivity.getPackageName());
 
@@ -311,30 +309,11 @@
             // reused either.
             LoadUrlParams loadUrlParams = new LoadUrlParams(url);
             loadUrlParams.setIntentReceivedTimestamp(intentTimestamp);
+            loadUrlParams.setVerbatimHeaders(headers);
             if (referer != null) {
                 loadUrlParams.setReferrer(
                         new Referrer(referer, IntentHandler.getReferrerPolicyFromIntent(intent)));
             }
-            // Handle post data case.
-            if (IntentHandler.wasIntentSenderChrome(intent)) {
-                String postDataType =
-                        IntentUtils.safeGetStringExtra(intent, IntentHandler.EXTRA_POST_DATA_TYPE);
-                byte[] postData =
-                        IntentUtils.safeGetByteArrayExtra(intent, IntentHandler.EXTRA_POST_DATA);
-                if (!TextUtils.isEmpty(postDataType) && postData != null && postData.length != 0) {
-                    StringBuilder appendToHeader = new StringBuilder();
-                    appendToHeader.append("Content-Type: ");
-                    appendToHeader.append(postDataType);
-                    if (TextUtils.isEmpty(headers)) {
-                        headers = appendToHeader.toString();
-                    } else {
-                        headers = headers + "\r\n" + appendToHeader.toString();
-                    }
-
-                    loadUrlParams.setPostData(ResourceRequestBody.createFromBytes(postData));
-                }
-            }
-            loadUrlParams.setVerbatimHeaders(headers);
             return createNewTab(loadUrlParams, TabLaunchType.FROM_EXTERNAL_APP, null, intent);
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
index e24dc82..befb76a6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
@@ -7,6 +7,8 @@
 import androidx.annotation.IntDef;
 
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
+import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
+import org.chromium.ui.modelutil.PropertyModel;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -133,4 +135,25 @@
 
     /** @return The height of the shadow above the bottom sheet in px. */
     int getTopShadowHeight();
+
+    /**
+     * @return The srcim's coordinator. This can be used to customize the bottom sheet's interaction
+     *         with the scrim if the default behavior is not desired -- fading in behind the sheet
+     *         as the sheet is expanded.
+     */
+    ScrimCoordinator getScrimCoordinator();
+
+    /**
+     * This method provides a property model that can be used to show the scrim behind the bottom
+     * sheet. This can be used in conjunction with {@link #getScrimCoordinator()} to customize the
+     * scrim's behavior. While this method is not required to show the scrim, this method returns
+     * a model set up to appear behnind the sheet. Common usage is the following:
+     *
+     * PropertyModel params = controller.createScrimParams();
+     * // further modify params
+     * controller.getScrimCoordinator().showScrim(params);
+     *
+     * @return A property model used to show the scrim behind the bottom sheet.
+     */
+    PropertyModel createScrimParams();
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerImpl.java
index f4b2e53..e7f1b395 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerImpl.java
@@ -24,8 +24,6 @@
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabObserver;
 import org.chromium.chrome.browser.vr.VrModuleProvider;
-import org.chromium.chrome.browser.widget.ScrimView.ScrimObserver;
-import org.chromium.chrome.browser.widget.ScrimView.ScrimParams;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
 import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
 import org.chromium.components.browser_ui.widget.scrim.ScrimProperties;
@@ -112,6 +110,9 @@
     /** The content being shown prior to the sheet being suppressed. */
     private BottomSheetContent mContentWhenSuppressed;
 
+    /** A means of accessing the ScrimCoordinator. */
+    private Supplier<ScrimCoordinator> mScrimCoordinatorSupplier;
+
     /**
      * Build a new controller of the bottom sheet.
      * @param activityTabProvider The provider of the activity's current tab.
@@ -131,6 +132,7 @@
         mOverlayPanelManager = overlayManager;
         mBrowserControlsStateProvider = fullscreenManager;
         mFullscreenManager = fullscreenManager;
+        mScrimCoordinatorSupplier = scrim;
         mPendingSheetObservers = new ArrayList<>();
 
         mPendingSheetObservers.add(new EmptyBottomSheetObserver() {
@@ -206,17 +208,17 @@
         };
 
         mSheetInitializer = () -> {
-            initializeSheet(scrim, bottomSheetViewSupplier, window, keyboardDelegate);
+            initializeSheet(bottomSheetViewSupplier, window, keyboardDelegate);
         };
     }
 
     /**
      * Do the actual initialization of the bottom sheet.
-     * @param scrim The scrim to show behind the sheet.
      * @param bottomSheetViewSupplier A means of creating the bottom sheet.
+     * @param window A means of accessing the screen size.
+     * @param keyboardDelegate A means of hiding the keyboard.
      */
-    private void initializeSheet(final Supplier<ScrimCoordinator> scrim,
-            Supplier<View> bottomSheetViewSupplier, Window window,
+    private void initializeSheet(Supplier<View> bottomSheetViewSupplier, Window window,
             KeyboardVisibilityDelegate keyboardDelegate) {
         mBottomSheet = (BottomSheet) bottomSheetViewSupplier.get();
         mBottomSheet.init(window, keyboardDelegate);
@@ -310,7 +312,7 @@
                     return;
                 }
 
-                scrim.get().showScrim(scrimProperties);
+                mScrimCoordinatorSupplier.get().showScrim(scrimProperties);
                 mScrimShown = true;
             }
 
@@ -318,7 +320,7 @@
             public void onSheetClosed(@StateChangeReason int reason) {
                 // Hide the scrim if the current content doesn't have a custom scrim lifecycle.
                 if (mScrimShown) {
-                    scrim.get().hideScrim(true);
+                    mScrimCoordinatorSupplier.get().hideScrim(true);
                     mScrimShown = false;
                 }
 
@@ -361,13 +363,25 @@
         mSheetInitializer = null;
     }
 
-    /**
-     * Create a ScrimParams anchoring on the bottom-sheet view.
-     * @param scrimObserver The scrimObserver to set for the ScrimParams.
-     */
-    public ScrimParams createScrimParams(ScrimObserver scrimObserver) {
-        return new ScrimParams(/*anchorView=*/mBottomSheet, /*showInFrontOfAnchorView=*/false,
-                /*affectsStatusBar=*/true, /*topMargin=*/0, /*observer*/ scrimObserver);
+    @Override
+    public ScrimCoordinator getScrimCoordinator() {
+        return mScrimCoordinatorSupplier.get();
+    }
+
+    @Override
+    public PropertyModel createScrimParams() {
+        return new PropertyModel.Builder(ScrimProperties.REQUIRED_KEYS)
+                .with(ScrimProperties.TOP_MARGIN, 0)
+                .with(ScrimProperties.AFFECTS_STATUS_BAR, true)
+                .with(ScrimProperties.ANCHOR_VIEW, mBottomSheet)
+                .with(ScrimProperties.SHOW_IN_FRONT_OF_ANCHOR_VIEW, false)
+                .with(ScrimProperties.CLICK_DELEGATE,
+                        () -> {
+                            if (!mBottomSheet.isSheetOpen()) return;
+                            mBottomSheet.setSheetState(mBottomSheet.getMinSwipableSheetState(),
+                                    true, StateChangeReason.TAP_SCRIM);
+                        })
+                .build();
     }
 
     // Destroyable implementation.
diff --git a/chrome/android/javatests/DEPS b/chrome/android/javatests/DEPS
index 430b355..2a27204 100644
--- a/chrome/android/javatests/DEPS
+++ b/chrome/android/javatests/DEPS
@@ -2,7 +2,6 @@
   "+chrome/app",
   "+chrome/browser/android/lifecycle",
   "+chrome/browser/profiles/android/java",
-  "+chrome/browser/share/android/java",
   "+chrome/browser/tab/java",
   "+chrome/browser/thumbnail/generator/android/java",
   "+chrome/browser/ui/android/appmenu",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunUtilsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunUtilsTest.java
index ba894b5..a6ead9a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunUtilsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunUtilsTest.java
@@ -50,7 +50,6 @@
         private final String mAccountType;
 
         FakeAuthenticationAccountManager(String accountType) {
-            super(FakeAccountManagerDelegate.DISABLE_PROFILE_DATA_SOURCE);
             mAccountType = accountType;
         }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
index c714919..1f90443 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
@@ -29,6 +29,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Matchers;
 import org.chromium.base.test.util.Restriction;
@@ -208,6 +209,7 @@
     @Test
     @SmallTest
     @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
+    @DisabledTest(message = "Flaky. See https://crbug.com/1091646")
     public void testShowingVoiceSearchButtonIfUrlBarIsEmpty() throws ExecutionException {
         // When there's no text, the mic button should be visible.
         setUrlBarTextAndFocus("");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/ExpandablePaymentHandlerCoordinatorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/ExpandablePaymentHandlerCoordinatorTest.java
deleted file mode 100644
index 08a13d7..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/ExpandablePaymentHandlerCoordinatorTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.payments;
-
-import android.support.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.payments.handler.PaymentHandlerCoordinator;
-import org.chromium.chrome.browser.payments.handler.PaymentHandlerCoordinator.PaymentHandlerUiObserver;
-import org.chromium.chrome.test.ChromeActivityTestRule;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.content_public.browser.test.util.Criteria;
-import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.url.GURL;
-
-/**
- * An integration test for {@link PaymentHandlerCoordinator}.
- */
-@RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-public class ExpandablePaymentHandlerCoordinatorTest {
-    @Rule
-    public ChromeActivityTestRule<ChromeActivity> mRule =
-            new ChromeActivityTestRule<>(ChromeActivity.class);
-
-    private boolean mUiShown = false;
-
-    @Before
-    public void setUp() {
-        mRule.startMainActivityOnBlankPage();
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"Payments"})
-    public void testShow() throws Throwable {
-        PaymentHandlerCoordinator paymentHandler = new PaymentHandlerCoordinator();
-        PaymentHandlerUiObserver uiObserver = new PaymentHandlerUiObserver() {
-            @Override
-            public void onPaymentHandlerUiClosed() {}
-
-            @Override
-            public void onPaymentHandlerUiShown() {
-                mUiShown = true;
-            }
-        };
-        mRule.runOnUiThread(
-                ()
-                        -> paymentHandler.show(mRule.getActivity(),
-                                new GURL("https://maxpay.com/pay"), /*isIncognito=*/false,
-                                /*webContentsObserver=*/(webContents) -> {}, uiObserver));
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mUiShown;
-            }
-        });
-
-        mRule.runOnUiThread(() -> paymentHandler.hide());
-    }
-}
\ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/ExpandablePaymentHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/ExpandablePaymentHandlerTest.java
index 05f72f8a..43703e4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/ExpandablePaymentHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/ExpandablePaymentHandlerTest.java
@@ -1,28 +1,11 @@
+package org.chromium.chrome.browser.payments;
+
 // Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.payments;
+import android.support.test.filters.MediumTest;
 
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-
-import static org.hamcrest.Matchers.startsWith;
-
-import android.os.RemoteException;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.UiSelector;
-
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -30,187 +13,59 @@
 
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.payments.handler.PaymentHandlerCoordinator;
+import org.chromium.chrome.browser.payments.handler.PaymentHandlerCoordinator.PaymentHandlerUiObserver;
+import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.components.payments.PaymentFeatureList;
+import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.net.test.EmbeddedTestServer;
-import org.chromium.net.test.ServerCertificate;
-
-import java.util.concurrent.TimeoutException;
+import org.chromium.url.GURL;
 
 /**
  * A test for the Expandable PaymentHandler {@link PaymentHandlerCoordinator}.
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
-        "enable-features=" + PaymentFeatureList.SCROLL_TO_EXPAND_PAYMENT_HANDLER})
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class ExpandablePaymentHandlerTest {
-    private static final long MAX_WAIT_UNTIL_EXISTS = 3000L;
-
-    // Open a tab on the blank page first to initiate the native bindings required by the test
-    // server.
     @Rule
-    public PaymentRequestTestRule mRule = new PaymentRequestTestRule("about:blank");
+    public ChromeActivityTestRule<ChromeActivity> mRule =
+            new ChromeActivityTestRule<>(ChromeActivity.class);
 
-    // Host the tests on https://127.0.0.1, because file:// URLs cannot have service workers.
-    private EmbeddedTestServer mServer;
-
-    private UiDevice mDevice;
+    private boolean mUiShown = false;
 
     @Before
-    public void setUp() throws Throwable {
-        mServer = EmbeddedTestServer.createAndStartHTTPSServer(
-                InstrumentationRegistry.getContext(), ServerCertificate.CERT_OK);
-        mRule.startMainActivityWithURL(
-                mServer.getURL("/components/test/data/payments/maxpay.com/merchant.html"));
-
-        // Find the web contents where JavaScript will be executed and instrument the browser
-        // payment sheet.
-        mRule.openPage();
-        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-    }
-
-    private UiObject showPaymentHandlerUi() throws TimeoutException {
-        mRule.clickNode("launch");
-        UiObject bottomSheet = mDevice.findObject(
-                new UiSelector().description("Payment handler sheet. Swipe down to close."));
-        Assert.assertTrue(bottomSheet.waitForExists(MAX_WAIT_UNTIL_EXISTS));
-        return bottomSheet;
-    }
-
-    private UiObject waitForTitleExists() {
-        UiObject title = mDevice.findObject(new UiSelector().text("Max Pay"));
-        Assert.assertTrue(title.waitForExists(MAX_WAIT_UNTIL_EXISTS));
-        return title;
-    }
-
-    private void clickCloseButton() {
-        onView(withId(org.chromium.chrome.R.id.close)).perform(click());
+    public void setUp() {
+        mRule.startMainActivityOnBlankPage();
     }
 
     @Test
-    @SmallTest
+    @MediumTest
     @Feature({"Payments"})
-    public void testCloseButtonCloseUi() throws TimeoutException {
-        UiObject bottomSheet = showPaymentHandlerUi();
-        Assert.assertTrue(bottomSheet.exists());
-        clickCloseButton();
-        Assert.assertFalse(bottomSheet.exists());
-    }
+    public void testShow() throws Throwable {
+        PaymentHandlerCoordinator paymentHandler = new PaymentHandlerCoordinator();
+        PaymentHandlerUiObserver uiObserver = new PaymentHandlerUiObserver() {
+            @Override
+            public void onPaymentHandlerUiClosed() {}
 
-    @Test
-    @SmallTest
-    @Feature({"Payments"})
-    public void testSwipeDownCloseUi() throws TimeoutException, UiObjectNotFoundException {
-        UiObject bottomSheet = showPaymentHandlerUi();
-        UiObject title = waitForTitleExists();
+            @Override
+            public void onPaymentHandlerUiShown() {
+                mUiShown = true;
+            }
+        };
+        mRule.runOnUiThread(
+                ()
+                        -> paymentHandler.show(mRule.getActivity(),
+                                new GURL("https://maxpay.com/pay"), /*isIncognito=*/false,
+                                /*webContentsObserver=*/(webContents) -> {}, uiObserver));
+        CriteriaHelper.pollInstrumentationThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return mUiShown;
+            }
+        });
 
-        Assert.assertTrue(bottomSheet.exists());
-        title.swipeDown(/*steps=*/10);
-        Assert.assertFalse(bottomSheet.exists());
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"Payments"})
-    public void testPressSystemBackAtFirstPageNotCloseUi() throws TimeoutException {
-        UiObject bottomSheet = showPaymentHandlerUi();
-        waitForTitleExists();
-
-        Assert.assertTrue(bottomSheet.exists());
-        Assert.assertFalse(mDevice.pressBack());
-        mDevice.waitForIdle();
-
-        Assert.assertTrue(bottomSheet.exists());
-        clickCloseButton();
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"Payments"})
-    public void testOrientationChange() throws TimeoutException, RemoteException {
-        UiObject bottomSheet = showPaymentHandlerUi();
-        waitForTitleExists();
-        Assert.assertTrue(bottomSheet.exists());
-
-        mDevice.setOrientationLeft();
-        mDevice.waitForIdle();
-        Assert.assertTrue(bottomSheet.exists());
-
-        mDevice.setOrientationRight();
-        mDevice.waitForIdle();
-        Assert.assertTrue(bottomSheet.exists());
-
-        mDevice.setOrientationNatural();
-        mDevice.waitForIdle();
-        Assert.assertTrue(bottomSheet.exists());
-
-        clickCloseButton();
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"Payments"})
-    public void testWebContentsExist() throws TimeoutException {
-        showPaymentHandlerUi();
-        CriteriaHelper.pollUiThread(
-                () -> PaymentRequestImpl.getPaymentHandlerWebContentsForTest() != null);
-        clickCloseButton();
-        CriteriaHelper.pollUiThread(
-                () -> PaymentRequestImpl.getPaymentHandlerWebContentsForTest() == null);
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"Payments"})
-    public void testUiElementsExist() throws TimeoutException {
-        showPaymentHandlerUi();
-        waitForTitleExists();
-        CriteriaHelper.pollUiThread(
-                () -> PaymentRequestImpl.getPaymentHandlerWebContentsForTest() != null);
-
-        onView(withId(org.chromium.chrome.R.id.title))
-                .check(matches(isDisplayed()))
-                .check(matches(withText("Max Pay")));
-        onView(withId(org.chromium.chrome.R.id.bottom_sheet))
-                .check(matches(isDisplayed()))
-                .check(matches(
-                        withContentDescription("Payment handler sheet. Swipe down to close.")));
-        onView(withId(org.chromium.chrome.R.id.close))
-                .check(matches(isDisplayed()))
-                .check(matches(withContentDescription("Close")));
-        onView(withId(org.chromium.chrome.R.id.security_icon))
-                .check(matches(isDisplayed()))
-                .check(matches(withContentDescription("Connection is secure. Site information")));
-        // Not verifying the port number because it's indefinite in tests.
-        onView(withId(org.chromium.chrome.R.id.origin))
-                .check(matches(isDisplayed()))
-                .check(matches(withText(startsWith("127.0.0.1:"))));
-
-        clickCloseButton();
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"Payments"})
-    public void testPageInfoButtonClickable() throws TimeoutException {
-        UiObject bottomSheet = showPaymentHandlerUi();
-        waitForTitleExists();
-
-        onView(withId(org.chromium.chrome.R.id.security_icon)).perform(click());
-        mDevice.waitForIdle();
-
-        String paymentAppUrl = mServer.getURL(
-                "/components/test/data/payments/maxpay.com/payment_handler_window.html");
-        onView(withId(org.chromium.chrome.R.id.page_info_url))
-                .check(matches(isDisplayed()))
-                .check(matches(withText(paymentAppUrl)));
-
-        Assert.assertFalse(bottomSheet.exists());
-        mDevice.pressBack();
-        Assert.assertTrue(bottomSheet.waitForExists(MAX_WAIT_UNTIL_EXISTS));
-        clickCloseButton();
+        mRule.runOnUiThread(() -> paymentHandler.hide());
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/query_tiles/QueryTileSectionToOmniboxTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/query_tiles/QueryTileSectionToOmniboxTest.java
index b0262a0..037089dc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/query_tiles/QueryTileSectionToOmniboxTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/query_tiles/QueryTileSectionToOmniboxTest.java
@@ -31,6 +31,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -130,6 +131,7 @@
     /** Test that clicking on a tile to open the omnibox and pressing back shows the right tiles. */
     @Test
     @SmallTest
+    @DisabledTest(message = "https://crbug.com/1091225")
     public void testBackOutOfOmniboxRestoresTilePosition() throws Exception {
         setUp(1 /* levels */);
         Matcher<View> recyclerViewMatcher = withParent(withId(R.id.query_tiles));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
index 29fed95..265407b2 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
@@ -12,18 +12,11 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.app.Instrumentation.ActivityMonitor;
-import android.content.Context;
 import android.content.Intent;
-import android.graphics.Bitmap;
-import android.net.Uri;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.text.TextUtils;
 import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.core.content.FileProvider;
 
 import org.junit.After;
 import org.junit.Assert;
@@ -36,9 +29,6 @@
 
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.Callback;
-import org.chromium.base.ContentUriUtils;
-import org.chromium.base.ContextUtils;
-import org.chromium.base.IntentUtils;
 import org.chromium.base.test.params.ParameterAnnotations;
 import org.chromium.base.test.params.ParameterSet;
 import org.chromium.base.test.params.ParameterizedRunner;
@@ -47,8 +37,6 @@
 import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
-import org.chromium.chrome.browser.IntentHandler;
-import org.chromium.chrome.browser.document.ChromeLauncherActivity;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.locale.DefaultSearchEngineDialogHelperUtils;
@@ -57,19 +45,14 @@
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.omnibox.OmniboxSuggestionType;
 import org.chromium.chrome.browser.omnibox.UrlBar;
-import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinatorTestUtils;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteResult;
 import org.chromium.chrome.browser.omnibox.suggestions.CachedZeroSuggestionsManager;
 import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestion;
 import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestionBuilderForTest;
-import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestionUiType;
-import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestionsDropdown;
 import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.searchwidget.SearchActivity.SearchActivityDelegate;
-import org.chromium.chrome.browser.share.clipboard.ClipboardImageFileProvider;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
 import org.chromium.chrome.test.MultiActivityTestRule;
 import org.chromium.chrome.test.util.ActivityUtils;
@@ -80,13 +63,9 @@
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.KeyUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
-import org.chromium.content_public.browser.test.util.TestTouchUtils;
 import org.chromium.content_public.common.ContentUrlConstants;
-import org.chromium.ui.base.Clipboard;
 import org.chromium.url.GURL;
 
-import java.io.ByteArrayOutputStream;
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -109,7 +88,6 @@
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class SearchActivityTest {
     private static final long OMNIBOX_SHOW_TIMEOUT_MS = 5000L;
-    private static final String TEST_PNG_IMAGE_FILE_EXTENSION = ".png";
 
     @ParameterAnnotations.ClassParameter
     private static List<ParameterSet> sClassParams =
@@ -178,25 +156,9 @@
         }
     }
 
-    // Helper class for clipboard Omnibox test.
-    private class FileProviderHelper implements ContentUriUtils.FileProviderUtil {
-        private static final String API_AUTHORITY_SUFFIX = ".FileProvider";
-
-        @Override
-        public Uri getContentUriFromFile(File file) {
-            Context appContext = ContextUtils.getApplicationContext();
-            return FileProvider.getUriForFile(
-                    appContext, appContext.getPackageName() + API_AUTHORITY_SUFFIX, file);
-        }
-    }
-
     @Rule
     public MultiActivityTestRule mTestRule = new MultiActivityTestRule();
 
-    @Rule
-    public ChromeActivityTestRule<ChromeTabbedActivity> mActivityTestRule =
-            new ChromeActivityTestRule<>(ChromeTabbedActivity.class);
-
     @Mock
     VoiceRecognitionHandler mHandler;
 
@@ -576,182 +538,6 @@
         });
     }
 
-    @Test
-    @SmallTest
-    @Features.
-    EnableFeatures({ChromeFeatureList.OMNIBOX_ENABLE_CLIPBOARD_PROVIDER_IMAGE_SUGGESTIONS})
-    public void testImageSearch() throws InterruptedException, Exception {
-        // Put an image into system clipboard.
-        putAnImageIntoClipboard();
-
-        // Start the Activity.
-        final SearchActivity searchActivity = startSearchActivity();
-
-        // Omnibox suggestions should appear now.
-        final SearchActivityLocationBarLayout locationBar =
-                (SearchActivityLocationBarLayout) searchActivity.findViewById(
-                        R.id.search_location_bar);
-        OmniboxTestUtils.waitForOmniboxSuggestions(locationBar, OMNIBOX_SHOW_TIMEOUT_MS);
-        waitForSuggestionType(locationBar, OmniboxSuggestionType.CLIPBOARD_IMAGE);
-        OmniboxSuggestionsDropdown suggestionsDropdown =
-                AutocompleteCoordinatorTestUtils.getSuggestionsDropdown(
-                        locationBar.getAutocompleteCoordinator());
-
-        int imageSuggestionIndex = -1;
-        // Find the index of the image clipboard suggestion.
-        for (int i = 0; i < suggestionsDropdown.getItemCount(); ++i) {
-            OmniboxSuggestion suggestion = AutocompleteCoordinatorTestUtils.getOmniboxSuggestionAt(
-                    locationBar.getAutocompleteCoordinator(), i);
-            if (suggestion != null
-                    && suggestion.getType() == OmniboxSuggestionType.CLIPBOARD_IMAGE) {
-                imageSuggestionIndex = i;
-                break;
-            }
-        }
-        Assert.assertNotEquals(
-                "Cannot find the image clipboard Omnibox suggestion", -1, imageSuggestionIndex);
-
-        OmniboxSuggestion imageSuggestion = AutocompleteCoordinatorTestUtils.getOmniboxSuggestionAt(
-                locationBar.getAutocompleteCoordinator(), imageSuggestionIndex);
-        Assert.assertNotNull("The image clipboard suggestion should contains post content type.",
-                imageSuggestion.getPostContentType());
-        Assert.assertNotEquals(
-                "The image clipboard suggestion should not contains am empty post content type.", 0,
-                imageSuggestion.getPostContentType().length());
-        Assert.assertNotNull("The image clipboard suggestion should contains post data.",
-                imageSuggestion.getPostData());
-        Assert.assertNotEquals(
-                "The image clipboard suggestion should not contains am empty post data.", 0,
-                imageSuggestion.getPostData().length);
-
-        // Find the index of clipboard suggestion in the dropdown list.
-        final int clipboardSuggestionIndexInDropdown =
-                AutocompleteCoordinatorTestUtils.getIndexForFirstSuggestionOfType(
-                        locationBar.getAutocompleteCoordinator(),
-                        OmniboxSuggestionUiType.CLIPBOARD_SUGGESTION);
-        Assert.assertNotEquals("Cannot find the image clipboard Omnibox suggestion in UI.", -1,
-                clipboardSuggestionIndexInDropdown);
-
-        // Make sure the new tab is launched.
-        final ChromeTabbedActivity cta = ActivityUtils.waitForActivity(
-                InstrumentationRegistry.getInstrumentation(), ChromeTabbedActivity.class,
-                new Callable<Void>() {
-                    @Override
-                    public Void call() throws InterruptedException {
-                        clickSuggestionAt(suggestionsDropdown, clipboardSuggestionIndexInDropdown);
-                        return null;
-                    }
-                });
-
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                Tab tab = cta.getActivityTab();
-                if (tab == null) return false;
-                // Make sure tab is in either upload page or result page. cannot only verify one of
-                // them since on fast device tab jump to result page really quick but on slow device
-                // may stay on upload page for a really long time.
-                return tab.getUrlString().equals(imageSuggestion.getUrl().getSpec())
-                        || TemplateUrlServiceFactory.get()
-                                   .isSearchResultsPageFromDefaultSearchProvider(
-                                           tab.getUrlString());
-            }
-        });
-    }
-
-    @Test
-    @SmallTest
-    @Features.
-    EnableFeatures({ChromeFeatureList.OMNIBOX_ENABLE_CLIPBOARD_PROVIDER_IMAGE_SUGGESTIONS})
-    public void testImageSearch_OnlyTrustedIntentCanPost() throws InterruptedException, Exception {
-        // Put an image into system clipboard.
-        putAnImageIntoClipboard();
-
-        // Start the Activity.
-        final SearchActivity searchActivity = startSearchActivity();
-
-        // Omnibox suggestions should appear now.
-        final SearchActivityLocationBarLayout locationBar =
-                (SearchActivityLocationBarLayout) searchActivity.findViewById(
-                        R.id.search_location_bar);
-        OmniboxTestUtils.waitForOmniboxSuggestions(locationBar, OMNIBOX_SHOW_TIMEOUT_MS);
-        waitForSuggestionType(locationBar, OmniboxSuggestionType.CLIPBOARD_IMAGE);
-        OmniboxSuggestionsDropdown suggestionsDropdown =
-                AutocompleteCoordinatorTestUtils.getSuggestionsDropdown(
-                        locationBar.getAutocompleteCoordinator());
-
-        int imageSuggestionIndex = -1;
-        // Find the index of the image clipboard suggestion.
-        for (int i = 0; i < suggestionsDropdown.getItemCount(); ++i) {
-            OmniboxSuggestion suggestion = AutocompleteCoordinatorTestUtils.getOmniboxSuggestionAt(
-                    locationBar.getAutocompleteCoordinator(), i);
-            if (suggestion != null
-                    && suggestion.getType() == OmniboxSuggestionType.CLIPBOARD_IMAGE) {
-                imageSuggestionIndex = i;
-                break;
-            }
-        }
-        Assert.assertNotEquals(
-                "Cannot find the image clipboard Omnibox suggestion", -1, imageSuggestionIndex);
-
-        OmniboxSuggestion imageSuggestion = AutocompleteCoordinatorTestUtils.getOmniboxSuggestionAt(
-                locationBar.getAutocompleteCoordinator(), imageSuggestionIndex);
-
-        Intent intent =
-                new Intent(Intent.ACTION_VIEW, Uri.parse(imageSuggestion.getUrl().getSpec()));
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
-        intent.setClass(searchActivity, ChromeLauncherActivity.class);
-        intent.putExtra(IntentHandler.EXTRA_POST_DATA_TYPE, imageSuggestion.getPostContentType());
-        intent.putExtra(IntentHandler.EXTRA_POST_DATA, imageSuggestion.getPostData());
-
-        final ChromeTabbedActivity cta =
-                ActivityUtils.waitForActivity(InstrumentationRegistry.getInstrumentation(),
-                        ChromeTabbedActivity.class, new Callable<Void>() {
-                            @Override
-                            public Void call() {
-                                IntentUtils.safeStartActivity(searchActivity, intent);
-                                return null;
-                            }
-                        });
-
-        // Because no POST data, Google wont go to the result page.
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                Tab tab = cta.getActivityTab();
-                return !TemplateUrlServiceFactory.get()
-                                .isSearchResultsPageFromDefaultSearchProvider(tab.getUrlString());
-            }
-        });
-    }
-
-    private void putAnImageIntoClipboard() {
-        mActivityTestRule.startMainActivityFromLauncher();
-        ContentUriUtils.setFileProviderUtil(new FileProviderHelper());
-        Bitmap bitmap =
-                Bitmap.createBitmap(/* width = */ 10, /* height = */ 10, Bitmap.Config.ARGB_8888);
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        bitmap.compress(Bitmap.CompressFormat.PNG, /*quality = (0-100) */ 100, baos);
-        byte[] mTestImageData = baos.toByteArray();
-        Clipboard.getInstance().setImageFileProvider(new ClipboardImageFileProvider());
-        Clipboard.getInstance().setImage(mTestImageData, TEST_PNG_IMAGE_FILE_EXTENSION);
-
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return Clipboard.getInstance().getImage() != null;
-            }
-        });
-    }
-
-    private void clickSuggestionAt(OmniboxSuggestionsDropdown suggestionsDropdown, int index)
-            throws InterruptedException {
-        // Wait a bit since the button may not able to click.
-        ViewGroup viewGroup = suggestionsDropdown.getViewGroup();
-        View view = viewGroup.getChildAt(index);
-        TestTouchUtils.singleClickView(InstrumentationRegistry.getInstrumentation(), view);
-    }
-
     private SearchActivity startSearchActivity() {
         return startSearchActivity(0, /*isVoiceSearch=*/false);
     }
@@ -797,29 +583,6 @@
         }));
     }
 
-    private void waitForSuggestionType(final SearchActivityLocationBarLayout locationBar,
-            final @OmniboxSuggestionType int type) {
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                OmniboxSuggestionsDropdown suggestionsDropdown =
-                        AutocompleteCoordinatorTestUtils.getSuggestionsDropdown(
-                                locationBar.getAutocompleteCoordinator());
-                if (suggestionsDropdown == null) return false;
-
-                for (int i = 0; i < suggestionsDropdown.getItemCount(); i++) {
-                    OmniboxSuggestion suggestion =
-                            AutocompleteCoordinatorTestUtils.getOmniboxSuggestionAt(
-                                    locationBar.getAutocompleteCoordinator(), i);
-                    if (suggestion != null && suggestion.getType() == type) {
-                        return true;
-                    }
-                }
-                return false;
-            }
-        });
-    }
-
     @SuppressLint("SetTextI18n")
     private void setUrlBarText(final Activity activity, final String url) {
         CriteriaHelper.pollUiThread(new Criteria() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java
index 8ee802d..889a3dd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java
@@ -148,6 +148,73 @@
     @Test
     @SmallTest
     @Feature({"Sync"})
+    @Features.EnableFeatures(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)
+    public void testUnsettingAllDataTypesStopsSync() {
+        mSyncTestRule.setUpAccountAndSignInForTesting();
+        SyncTestUtil.waitForSyncActive();
+
+        ManageSyncSettings fragment = startManageSyncPreferences();
+        assertSyncOnState(fragment);
+        mSyncTestRule.togglePreference(getSyncEverything(fragment));
+
+        for (CheckBoxPreference dataType : getDataTypes(fragment).values()) {
+            mSyncTestRule.togglePreference(dataType);
+        }
+        // All data types have been unchecked. Sync should stop.
+        Assert.assertFalse(SyncTestUtil.isSyncRequested());
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Sync"})
+    @Features.EnableFeatures(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)
+    public void testSettingAnyDataTypeStartsSync() {
+        mSyncTestRule.setUpAccountAndSignInForTesting();
+        mSyncTestRule.setChosenDataTypes(false, new HashSet<>());
+        mSyncTestRule.stopSync();
+        ManageSyncSettings fragment = startManageSyncPreferences();
+
+        CheckBoxPreference syncAutofill =
+                (CheckBoxPreference) fragment.findPreference(ManageSyncSettings.PREF_SYNC_AUTOFILL);
+        mSyncTestRule.togglePreference(syncAutofill);
+        // Sync should start after any data type is checked.
+        Assert.assertTrue(SyncTestUtil.isSyncRequested());
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Sync"})
+    @Features.EnableFeatures(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)
+    public void testTogglingSyncEverythingStartsSync() {
+        mSyncTestRule.setUpAccountAndSignInForTesting();
+        mSyncTestRule.setChosenDataTypes(false, new HashSet<>());
+        mSyncTestRule.stopSync();
+        ManageSyncSettings fragment = startManageSyncPreferences();
+
+        mSyncTestRule.togglePreference(getSyncEverything(fragment));
+        // Sync should start after setting sync everything toggle.
+        Assert.assertTrue(SyncTestUtil.isSyncRequested());
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Sync"})
+    @Features.EnableFeatures(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)
+    public void testTogglingSyncEverythingDoesNotStopSync() {
+        mSyncTestRule.setUpAccountAndSignInForTesting();
+        mSyncTestRule.setChosenDataTypes(false, new HashSet<>());
+        mSyncTestRule.startSync();
+        ManageSyncSettings fragment = startManageSyncPreferences();
+
+        // Sync is requested to start. Toggling SyncEverything will call setChosenDataTypes with
+        // empty set in the backend. But sync stop request should not be called.
+        mSyncTestRule.togglePreference(getSyncEverything(fragment));
+        Assert.assertTrue(SyncTestUtil.isSyncRequested());
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Sync"})
     public void testPaymentsIntegrationChecked() {
         mSyncTestRule.setUpAccountAndSignInForTesting();
         mSyncTestRule.setPaymentsIntegrationEnabled(true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrPermissionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrPermissionTest.java
index a13fce0ea..4b0728d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrPermissionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrPermissionTest.java
@@ -22,6 +22,7 @@
 import org.chromium.base.test.params.ParameterSet;
 import org.chromium.base.test.params.ParameterizedRunner;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.vr.rules.XrActivityRestriction;
@@ -89,7 +90,11 @@
     @Test
     @MediumTest
     @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
-    public void testVrPermissionPersistance() {
+    @DisabledTest(
+            message =
+                    "https://crbug.com/1091482, https://crbug.com/1091465, https://crbug.com/1091433")
+    public void
+    testVrPermissionPersistance() {
         mWebXrVrPermissionTestFramework.loadFileAndAwaitInitialization(
                 "generic_webxr_page", PAGE_LOAD_TIMEOUT_S);
         mWebXrVrPermissionTestFramework.enterSessionWithUserGestureOrFail();
@@ -126,7 +131,11 @@
     @Test
     @MediumTest
     @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
-    public void testPermissionPersistsAfterReload() {
+    @DisabledTest(
+            message =
+                    "https://crbug.com/1091483, https://crbug.com/1091476, https://crbug.com/1091463")
+    public void
+    testPermissionPersistsAfterReload() {
         mWebXrVrPermissionTestFramework.loadFileAndAwaitInitialization(
                 "generic_webxr_page", PAGE_LOAD_TIMEOUT_S);
 
diff --git a/chrome/app/OWNERS b/chrome/app/OWNERS
index b7554c7..6116ffa6 100644
--- a/chrome/app/OWNERS
+++ b/chrome/app/OWNERS
@@ -36,8 +36,6 @@
 per-file supervised_user_error_page_strings.grdp=file://chrome/browser/supervised_user/supervised_user_error_page/OWNERS
 
 per-file vr_strings.grdp=file://chrome/browser/vr/OWNERS
-per-file xr_consent_ui_strings.grdp=file://chrome/browser/vr/OWNERS
-per-file xr_support_ui_strings.grdp=file://chrome/browser/vr/OWNERS
 
 # Non-GRD rules.
 
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 3c3245e..2cfc198 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -4311,6 +4311,12 @@
   <message name="IDS_CROSTINI_INSTALLER_USERNAME_NOT_AVAILABLE_ERROR" desc="Text shown in the Crostini installer dialog when the user picks a username that is not available">
     Username "<ph name="USERNAME">$1<ex>root</ex></ph>" is not available
   </message>
+  <message name="IDS_CROSTINI_INSTALLER_RECOMMENDED_DISK_SIZE_LABEL" desc="Label for the radio button in the Crostini installer dialog to pick the recommended disk size">
+    Recommended (<ph name="INSTALL_SIZE">$1<ex>1.3GB</ex></ph>)
+  </message>
+  <message name="IDS_CROSTINI_INSTALLER_CUSTOM_DISK_SIZE_LABEL" desc="Label for the radio button in the Crostini installer dialog to pick a custom disk size">
+    Custom
+  </message>
   <message name="IDS_CROSTINI_UNINSTALLER_TITLE" desc="Title of the Crostini uninstaller, a dialog for uninstalling Linux, the associated VM and Linux files.">
     Delete Linux (Beta)
   </message>
@@ -4336,7 +4342,7 @@
     Upgrade Linux (Beta)
   </message>
   <message name="IDS_CROSTINI_UPGRADER_BODY" desc="Description for the Crostini upgrader, a dialog for upgrading Linux.">
-    We recommend you back up your current Linux container prior to upgrading.
+    Backing up files is recommended as part of this upgrade to prevent data loss in case the upgrade cannot be completed. Starting the upgrade will cause Linux (Beta) to shut down. Please save open files before proceeding.
   </message>
   <message name="IDS_CROSTINI_UPGRADER_UPGRADE_BUTTON" desc="Label for the button in the Crostini upgrader dialog to begin upgrading Linux.">
     Upgrade
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_UPGRADER_BODY.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_UPGRADER_BODY.png.sha1
new file mode 100644
index 0000000..ab2fd6c
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_UPGRADER_BODY.png.sha1
@@ -0,0 +1 @@
+b64d3b1e7d85a297e917069c7213221e208b23cf
\ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index bcd8bae..eb3fbc5 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -317,9 +317,6 @@
       <!-- Strings that are only used when VR devices are supported -->
       <if expr="enable_vr">
         <part file="vr_strings.grdp" />
-        <if expr="not is_android">
-          <part file="xr_consent_ui_strings.grdp" />
-        </if>
       </if>
 
       <!-- Supervised user error page -->
@@ -4625,7 +4622,7 @@
         Change back to Google?
       </message>
       <message name="IDS_EXTENSION_NTP_OVERRIDDEN_DIALOG_BODY_GENERIC" desc="The body of the dialog informing the user that the new tab page has been overridden by an extension, indicating which extension now controls it.">
-        This page was changed by the <ph name="EXTENSION_NAME">$1<ex>Google Arts and Culture</ex></ph> extension
+        This page was changed by the "<ph name="EXTENSION_NAME">$1<ex>Google Arts and Culture</ex></ph>" extension
       </message>
       <message name="IDS_EXTENSION_SEARCH_OVERRIDDEN_DIALOG_TITLE_GENERIC" desc="The title of the dialog informing the user that the default search engine has been overridden by an extension.">
         Did you mean to change your search provider?
@@ -4637,7 +4634,7 @@
         Change back to <ph name="OLD_SEARCH_PROVIDER">$1<ex>DuckDuckGo</ex></ph>?
       </message>
       <message name="IDS_EXTENSION_SEARCH_OVERRIDDEN_DIALOG_BODY_GENERIC" desc="The body of the dialog informing the user that the default search engine has been overridden by an extension, indicating which extension now controls it.">
-        The <ph name="EXTENSION_NAME">$2<ex>Some New Search</ex></ph> extension changed search to use <ph name="SEARCH_PROVIDER_DOMAIN">$1<ex>google.com</ex></ph>
+        The "<ph name="EXTENSION_NAME">$2<ex>Some New Search</ex></ph>" extension changed search to use <ph name="SEARCH_PROVIDER_DOMAIN">$1<ex>google.com</ex></ph>
       </message>
       <!-- End Extension Settings Overridden Dialog strings. -->
 
diff --git a/chrome/app/os_settings_search_tag_strings.grdp b/chrome/app/os_settings_search_tag_strings.grdp
index 740998f..677ae095 100644
--- a/chrome/app/os_settings_search_tag_strings.grdp
+++ b/chrome/app/os_settings_search_tag_strings.grdp
@@ -659,6 +659,9 @@
   <message name="IDS_OS_SETTINGS_TAG_ASSISTANT_TURN_ON_ALT1" desc="Text for search result item which, when clicked, navigates the user to Google Assistant settings, with an option to turn functionality on. Alternate phrase for: 'Turn on Google Assistant'">
     Enable Google Assistant
   </message>
+  <message name="IDS_OS_SETTINGS_TAG_ASSISTANT_TRAIN_VOICE_MODEL" desc="Text for search result item which, when clicked, navigates the user to Google Assistant settings, with an option to train a voice model to listen for commands such as 'Okay Google' or 'Hey Google'">
+    Train Google Assistant voice model
+  </message>
 
   <!-- Apps section. -->
   <message name="IDS_OS_SETTINGS_TAG_APPS" desc="Text for search result item which, when clicked, navigates the user to apps settings.">
diff --git a/chrome/app/resources/generated_resources_cs.xtb b/chrome/app/resources/generated_resources_cs.xtb
index 754bf99..e82626df 100644
--- a/chrome/app/resources/generated_resources_cs.xtb
+++ b/chrome/app/resources/generated_resources_cs.xtb
@@ -2184,6 +2184,7 @@
 <translation id="3732857534841813090">Informace související s Asistentem Google</translation>
 <translation id="3733127536501031542">Server SSL s technologií Step-up</translation>
 <translation id="3735740477244556633">Seřadit podle</translation>
+<translation id="3738213647660363521">Vlastní barva kurzoru</translation>
 <translation id="3738924763801731196"><ph name="OID" />:</translation>
 <translation id="3739254215541673094">Spustit aplikaci <ph name="APPLICATION" />?</translation>
 <translation id="3742055079367172538">Byl vytvořen snímek obrazovky</translation>
@@ -3295,6 +3296,7 @@
 <translation id="52232769093306234">Zabalení se nezdařilo.</translation>
 <translation id="5225324770654022472">Zobrazit zástupce aplikací</translation>
 <translation id="5227679487546032910">Výchozí šedozelený avatar</translation>
+<translation id="5228088094491423618">Okamžitý přepis</translation>
 <translation id="5228579091201413441">Aktivace synchronizace</translation>
 <translation id="5229189185761556138">Spravovat metody zadávání</translation>
 <translation id="5230516054153933099">Okno</translation>
@@ -6348,6 +6350,7 @@
 <translation id="9121814364785106365">Otevřít jako připnutou kartu</translation>
 <translation id="9122176249172999202">Prohlížeč <ph name="IDS_SHORT_PRODUCT_NAME" /> je pozastaven</translation>
 <translation id="9124003689441359348">Zde se zobrazí uložená hesla</translation>
+<translation id="9126149354162942022">Barva kurzoru</translation>
 <translation id="9128317794749765148">Instalaci nebylo možné dokončit</translation>
 <translation id="9128870381267983090">Připojit k síti</translation>
 <translation id="9130015405878219958">Byl zadán neplatný režim.</translation>
diff --git a/chrome/app/resources/generated_resources_de.xtb b/chrome/app/resources/generated_resources_de.xtb
index 7521a7e..9946cca 100644
--- a/chrome/app/resources/generated_resources_de.xtb
+++ b/chrome/app/resources/generated_resources_de.xtb
@@ -418,7 +418,7 @@
 <translation id="1526560967942511387">Unbenanntes Dokument</translation>
 <translation id="1527336312600375509">Monitoraktualisierungsrate</translation>
 <translation id="1529891865407786369">Stromquelle</translation>
-<translation id="1530838837447122178">Einstellungen für Maus- und Touchpadgeräte öffnen</translation>
+<translation id="1530838837447122178">Geräteeinstellungen für Maus und Touchpad öffnen</translation>
 <translation id="1531004739673299060">Anwendungsfenster</translation>
 <translation id="1531275250079031713">Dialogfeld "Anderes WLAN hinzufügen" anzeigen</translation>
 <translation id="1536754031901697553">Verbindung wird getrennt…</translation>
diff --git a/chrome/app/resources/generated_resources_es-419.xtb b/chrome/app/resources/generated_resources_es-419.xtb
index a7a8c3b..21e90bdb 100644
--- a/chrome/app/resources/generated_resources_es-419.xtb
+++ b/chrome/app/resources/generated_resources_es-419.xtb
@@ -499,7 +499,7 @@
 <translation id="1629314197035607094">Caducó la contraseña</translation>
 <translation id="1630768113285622200">Restablecer y continuar</translation>
 <translation id="1630873818549593964">Los datos de tu hijo en Classroom estarán protegidos. <ph name="LINK_BEGIN" />Más información<ph name="LINK_END" /></translation>
-<translation id="1632082166874334883">Contraseña almacenada en tu Cuenta de Google</translation>
+<translation id="1632082166874334883">Contraseñas almacenadas en tu Cuenta de Google</translation>
 <translation id="1632803087685957583">Permite ajustar la velocidad de repetición del teclado, la predicción de palabras y más</translation>
 <translation id="1633947793238301227">Inhabilitar el Asistente de Google</translation>
 <translation id="1634783886312010422">¿Ya cambiaste esta contraseña en <ph name="WEBSITE" />?</translation>
@@ -1572,7 +1572,7 @@
 <translation id="296026337010986570">Se quitó el software dañino. Para volver a activar las extensiones, visita la sección &lt;a href="chrome://extensions"&gt;Extensiones&lt;/a&gt;.</translation>
 <translation id="2961090598421146107"><ph name="CERTIFICATE_NAME" /> (extensión proporcionada)</translation>
 <translation id="2961695502793809356">Haz clic para continuar o espera para ver el historial</translation>
-<translation id="2962131322798295505">Selector de fondos de pantalla</translation>
+<translation id="2962131322798295505">Wallpaper Picker</translation>
 <translation id="2963151496262057773">El siguiente complemento no responde: <ph name="PLUGIN_NAME" /> ¿Quieres detenerlo?</translation>
 <translation id="2964193600955408481">Desactivar Wi-Fi</translation>
 <translation id="2966937470348689686">Administrar las preferencias de Android</translation>
@@ -2122,6 +2122,7 @@
 <translation id="3677106374019847299">Ingresar un proveedor personalizado</translation>
 <translation id="3677657024345889897">Mínimo</translation>
 <translation id="3677911431265050325">Solicitar sitio móvil</translation>
+<translation id="3677959414150797585">Incluye apps, páginas web y mucho más. Envía estadísticas para mejorar las sugerencias solo si elegiste compartir los datos de uso.</translation>
 <translation id="3678156199662914018">Extensión: <ph name="EXTENSION_NAME" /></translation>
 <translation id="3680683624079082902">Voz para texto a voz</translation>
 <translation id="3681311097828166361">Gracias por tus comentarios. Tu informe se enviará cuando tengas conexión.</translation>
@@ -3774,6 +3775,7 @@
 <translation id="5835486486592033703"><ph name="WINDOW_TITLE" />: La cámara o el micrófono están grabando</translation>
 <translation id="5841270259333717135">Configurar Ethernet</translation>
 <translation id="5842497610951477805">Activación de Bluetooth</translation>
+<translation id="5844574845205796324">Sugerir nuevo contenido para explorar</translation>
 <translation id="5846200638699387931">Error de sintaxis relacional: <ph name="ERROR_LINE" /></translation>
 <translation id="5846807460505171493">Instala actualizaciones y apps. Si continúas, aceptas que este dispositivo también descargue e instale automáticamente actualizaciones y apps de Google, tu proveedor y el fabricante del dispositivo usando datos móviles. Es posible que algunas de estas apps ofrezcan compras directas desde la aplicación.</translation>
 <translation id="5849212445710944278">Ya se agregó</translation>
diff --git a/chrome/app/resources/generated_resources_eu.xtb b/chrome/app/resources/generated_resources_eu.xtb
index cf6635a..c43636a4b 100644
--- a/chrome/app/resources/generated_resources_eu.xtb
+++ b/chrome/app/resources/generated_resources_eu.xtb
@@ -502,7 +502,7 @@
 <translation id="1629314197035607094">Pasahitza iraungi egin da</translation>
 <translation id="1630768113285622200">Berrabiarazi eta egin aurrera</translation>
 <translation id="1630873818549593964">Haurraren datuak babestuta egongo dira Classroom-en. <ph name="LINK_BEGIN" />Lortu informazio gehiago<ph name="LINK_END" /></translation>
-<translation id="1632082166874334883">Gorde dira pasahitzak Google-ko kontuan</translation>
+<translation id="1632082166874334883">Pasahitza Google-ko kontuan dago gordeta</translation>
 <translation id="1632803087685957583">Teklak sakatuta edukitzean, idatzitakoa zenbat aldiz errepikatuko den, hitzen iragarpena erabiliko den eta beste zenbait gauza doitzeko aukera ematen dizu</translation>
 <translation id="1633947793238301227">Desgaitu Google-ren Laguntzailea</translation>
 <translation id="1634783886312010422">Aldatu al duzu pasahitza <ph name="WEBSITE" /> webgunean?</translation>
diff --git a/chrome/app/resources/generated_resources_fil.xtb b/chrome/app/resources/generated_resources_fil.xtb
index 23ee4f0..f7f012e0 100644
--- a/chrome/app/resources/generated_resources_fil.xtb
+++ b/chrome/app/resources/generated_resources_fil.xtb
@@ -2185,6 +2185,7 @@
 <translation id="3732857534841813090">Impormasyong nauugnay sa Google Assistant</translation>
 <translation id="3733127536501031542">SSL Server na may Step-up</translation>
 <translation id="3735740477244556633">Pagbukud-bukurin ayon sa</translation>
+<translation id="3738213647660363521">Custom na kulay ng cursor</translation>
 <translation id="3738924763801731196"><ph name="OID" />:</translation>
 <translation id="3739254215541673094">Buksan ang <ph name="APPLICATION" />?</translation>
 <translation id="3742055079367172538">Nakakuha na ng screenshot</translation>
@@ -3297,6 +3298,7 @@
 <translation id="52232769093306234">Hindi nagtagumpay ang pag-pack.</translation>
 <translation id="5225324770654022472">Ipakita ang shortcut ng mga app</translation>
 <translation id="5227679487546032910">Default na teal na avatar</translation>
+<translation id="5228088094491423618">Mga Instant Caption</translation>
 <translation id="5228579091201413441">I-enable ang pag-sync</translation>
 <translation id="5229189185761556138">Pamahalaan ang mga paraan ng pag-input</translation>
 <translation id="5230516054153933099">Window</translation>
@@ -6353,6 +6355,7 @@
 <translation id="9121814364785106365">Binuksan bilang na-pin na tab</translation>
 <translation id="9122176249172999202">Naka-pause ang <ph name="IDS_SHORT_PRODUCT_NAME" /></translation>
 <translation id="9124003689441359348">Lalabas dito ang mga na-save na password</translation>
+<translation id="9126149354162942022">Kulay ng cursor</translation>
 <translation id="9128317794749765148">Hindi makumpleto ang pag-set up</translation>
 <translation id="9128870381267983090">Kumonekta sa network</translation>
 <translation id="9130015405878219958">Di-wastong mode ang ipinasok.</translation>
diff --git a/chrome/app/resources/generated_resources_fr-CA.xtb b/chrome/app/resources/generated_resources_fr-CA.xtb
index 85fef6a..992aa118 100644
--- a/chrome/app/resources/generated_resources_fr-CA.xtb
+++ b/chrome/app/resources/generated_resources_fr-CA.xtb
@@ -2186,6 +2186,7 @@
 <translation id="3732857534841813090">Renseignements connexes, Assistant Google</translation>
 <translation id="3733127536501031542">Serveur SSL avec fonction d'optimisation</translation>
 <translation id="3735740477244556633">Trier par</translation>
+<translation id="3738213647660363521">Couleur personnalisée pour le curseur</translation>
 <translation id="3738924763801731196"><ph name="OID" /> :</translation>
 <translation id="3739254215541673094">Ouvrir l'application <ph name="APPLICATION" />?</translation>
 <translation id="3742055079367172538">Saisie d'écran enregistrée</translation>
@@ -3298,6 +3299,7 @@
 <translation id="52232769093306234">Échec de l'emballage.</translation>
 <translation id="5225324770654022472">Afficher le raccourci des applications</translation>
 <translation id="5227679487546032910">Avatar bleu sarcelle par défaut</translation>
+<translation id="5228088094491423618">Transcription instantanée</translation>
 <translation id="5228579091201413441">Activer la synchronisation</translation>
 <translation id="5229189185761556138">Gérer les méthodes d'entrée</translation>
 <translation id="5230516054153933099">Fenêtre</translation>
@@ -6351,6 +6353,7 @@
 <translation id="9121814364785106365">Ouvrir dans un onglet épinglé</translation>
 <translation id="9122176249172999202">L'application <ph name="IDS_SHORT_PRODUCT_NAME" /> est interrompue</translation>
 <translation id="9124003689441359348">Les mots de passe enregistrés s'afficheront ici</translation>
+<translation id="9126149354162942022">Couleur du curseur</translation>
 <translation id="9128317794749765148">Impossible de terminer la configuration</translation>
 <translation id="9128870381267983090">Connexion au réseau</translation>
 <translation id="9130015405878219958">Le mode indiqué est incorrect.</translation>
diff --git a/chrome/app/resources/generated_resources_ja.xtb b/chrome/app/resources/generated_resources_ja.xtb
index ac7a2f10..f2d1c15 100644
--- a/chrome/app/resources/generated_resources_ja.xtb
+++ b/chrome/app/resources/generated_resources_ja.xtb
@@ -2184,6 +2184,7 @@
 <translation id="3732857534841813090">Google アシスタントの関連情報</translation>
 <translation id="3733127536501031542">International Step-UP 対応の SSL サーバー</translation>
 <translation id="3735740477244556633">並べ替え</translation>
+<translation id="3738213647660363521">カスタムのカーソルの色</translation>
 <translation id="3738924763801731196"><ph name="OID" />:</translation>
 <translation id="3739254215541673094"><ph name="APPLICATION" /> を開きますか?</translation>
 <translation id="3742055079367172538">スクリーンショット撮影完了</translation>
@@ -3296,6 +3297,7 @@
 <translation id="52232769093306234">圧縮できませんでした。</translation>
 <translation id="5225324770654022472">アプリのショートカットを表示</translation>
 <translation id="5227679487546032910">デフォルトの青緑のアバター</translation>
+<translation id="5228088094491423618">自動字幕起こし</translation>
 <translation id="5228579091201413441">同期を有効にする</translation>
 <translation id="5229189185761556138">入力方法を管理</translation>
 <translation id="5230516054153933099">ウィンドウ</translation>
@@ -6349,6 +6351,7 @@
 <translation id="9121814364785106365">固定されたタブとして開く</translation>
 <translation id="9122176249172999202"><ph name="IDS_SHORT_PRODUCT_NAME" /> は一時停止中</translation>
 <translation id="9124003689441359348">保存したパスワードがここに表示されます</translation>
+<translation id="9126149354162942022">カーソルの色</translation>
 <translation id="9128317794749765148">セットアップを完了できませんでした</translation>
 <translation id="9128870381267983090">ネットワークに接続する</translation>
 <translation id="9130015405878219958">入力されたモードが無効です。</translation>
diff --git a/chrome/app/resources/generated_resources_mk.xtb b/chrome/app/resources/generated_resources_mk.xtb
index a4f9fc9..f84b7059 100644
--- a/chrome/app/resources/generated_resources_mk.xtb
+++ b/chrome/app/resources/generated_resources_mk.xtb
@@ -502,7 +502,7 @@
 <translation id="1629314197035607094">Лозинката е истечена</translation>
 <translation id="1630768113285622200">Рестартирај и продолжи</translation>
 <translation id="1630873818549593964">Податоците на вашето дете во Classroom ќе бидат заштитени. <ph name="LINK_BEGIN" />Дознајте повеќе<ph name="LINK_END" /></translation>
-<translation id="1632082166874334883">Лозинката е зачувавана на вашата сметка на Google</translation>
+<translation id="1632082166874334883">Лозинката е зачувана во вашата сметка на Google</translation>
 <translation id="1632803087685957583">Ви дозволува да ги приспособите стапката на повторување на тастатурата, предвидувањето зборови и др.</translation>
 <translation id="1633947793238301227">Оневозможување на „Помошникот на Google“</translation>
 <translation id="1634783886312010422">Дали веќе ја променивте лозинкава на <ph name="WEBSITE" />?</translation>
@@ -1575,7 +1575,7 @@
 <translation id="296026337010986570">Готово. Штетниот софтвер е отстранет. За да ги вклучите екстензиите повторно, одете на &lt;a href="chrome://extensions"&gt;Екстензии.&lt;/a&gt;</translation>
 <translation id="2961090598421146107"><ph name="CERTIFICATE_NAME" /> (обезбедена е екстензија)</translation>
 <translation id="2961695502793809356">Кликнете за да отидете нанапред, задржете за да ја видите историјата</translation>
-<translation id="2962131322798295505">Избирач на заднина</translation>
+<translation id="2962131322798295505">Избирач на тапет</translation>
 <translation id="2963151496262057773">Следниов приклучок не реагира: <ph name="PLUGIN_NAME" />Дали сакате да го запрете?</translation>
 <translation id="2964193600955408481">Оневозможи Wi-Fi</translation>
 <translation id="2966937470348689686">Управувајте со поставките за Android</translation>
@@ -2881,7 +2881,7 @@
 <translation id="4645676300727003670">&amp;Чувај</translation>
 <translation id="4646675363240786305">Порти</translation>
 <translation id="4647090755847581616">&amp;Затвори ја картичката</translation>
-<translation id="4647420311443994946">{0,select, tablet{Стартувај ја апликацијата кога ќе се најавите на вашиот таблет}computer{Стартувај ја апликацијата кога ќе се најавите на вашиот компјутер}other{Стартувај ја апликацијата кога ќе се најавите на вашиот уред.}}</translation>
+<translation id="4647420311443994946">{0,select, tablet{Стартувај ја апликацијата кога ќе се најавам на таблетот}computer{Стартувај ја апликацијата кога ќе се најавам на компјутерот}other{Стартувај ја апликацијата кога ќе се најавам на уредот}}</translation>
 <translation id="4647697156028544508">Внесете PIN за „<ph name="DEVICE_NAME" />“.</translation>
 <translation id="4648491805942548247">Недоволно дозволи</translation>
 <translation id="4648499713050786492">Отклучете го профилот пред да додадете некого.</translation>
@@ -2894,7 +2894,7 @@
 <translation id="4660540330091848931">Се менува големината</translation>
 <translation id="4660838440047236328">распоредот на вашата соба</translation>
 <translation id="4661407454952063730">Податоци од апликација се сите податоци што ги зачувала некоја апликација (според поставките на програмерот), вклучувајќи податоци како што се контакти, пораки и фотографии.</translation>
-<translation id="4662373422909645029">Прекар не може да има бројки</translation>
+<translation id="4662373422909645029">Прекарот не може да содржи броеви</translation>
 <translation id="4662788913887017617">Споделете го обележувачов со вашиот iPhone</translation>
 <translation id="4663373278480897665">Камерата е дозволена</translation>
 <translation id="4664482161435122549">PKCS #12 Грешка при извезување</translation>
@@ -5543,7 +5543,7 @@
     <ph name="BEGIN_PARAGRAPH5" />Услугава може да ја исклучите во „Поставки“.<ph name="END_PARAGRAPH5" /></translation>
 <translation id="80974698889265265">PIN-кодовите не се поклопуваат</translation>
 <translation id="809792523045608178"><ph name="IDS_SHORT_PRODUCT_NAME" /> користи поставки за прокси од екстензија</translation>
-<translation id="8097959162767603171">Вашиот администратор прво мора да ги прифати условите на услугата на листата на уреди на Chrome на конзолата на администраторот.</translation>
+<translation id="8097959162767603171">Вашиот администратор прво мора да ги прифати „Условите за користење“ во списокот со уреди со Chrome во администраторската конзола.</translation>
 <translation id="8101987792947961127">Потребно е фабричко ресетирање на следното рестартирање</translation>
 <translation id="8102159139658438129">Одете во <ph name="LINK_BEGIN" />„Поставки“<ph name="LINK_END" /> за да видите опции за поврзаниот телефон</translation>
 <translation id="8104696615244072556">Фабрички ресетирајте го вашиот уред со <ph name="IDS_SHORT_PRODUCT_NAME" /> и вратете се на претходната верзија.</translation>
diff --git a/chrome/app/resources/generated_resources_ne.xtb b/chrome/app/resources/generated_resources_ne.xtb
index f13a573..7ccd337 100644
--- a/chrome/app/resources/generated_resources_ne.xtb
+++ b/chrome/app/resources/generated_resources_ne.xtb
@@ -2122,6 +2122,7 @@
 <translation id="3677106374019847299">आफूले रोजेको प्रदायकको नाम प्रविष्टि गर्नुहोस्</translation>
 <translation id="3677657024345889897">सबैभन्दा सानो आवाज</translation>
 <translation id="3677911431265050325">मोबाइल साइट अनुरोध गर्नुहोस्</translation>
+<translation id="3677959414150797585">एप, वेबपृष्ठ र अन्य कुराहरू समावेश हुन्छन्। तपाईंले प्रयोगसम्बन्धी डेटा सेयर गर्ने निर्णय गर्नुभएको छ भने मात्र सामग्री सिफारिस गर्ने सुविधा सुधार्ने प्रयोजनका लागि तथ्याङ्क पठाउँछ।</translation>
 <translation id="3678156199662914018">विस्तार: <ph name="EXTENSION_NAME" /></translation>
 <translation id="3680683624079082902">टेक्स्ट-टू-स्पिच सुविधाको आवाजसम्बन्धी सेटिङ</translation>
 <translation id="3681311097828166361">प्रतिक्रिया दिनुभएकोमा धन्यवाद। तपाईं अहिले अफलाइन हुनुहुन्छ र तपाईंको रिपोर्ट पछि पठाइने छ।</translation>
@@ -3773,6 +3774,7 @@
 <translation id="5835486486592033703"><ph name="WINDOW_TITLE" /> - क्यामेरा वा माइक्रोफोन मार्फत रेकर्डिङ</translation>
 <translation id="5841270259333717135">इथरनेट कन्फिगर गर्नुहोस्</translation>
 <translation id="5842497610951477805">ब्लुटुथ सक्षम</translation>
+<translation id="5844574845205796324">अन्वेषण गरिनु पर्ने नयाँ सामग्री सिफारिस गरियोस्</translation>
 <translation id="5846200638699387931">सम्बन्धको विन्याससम्बन्धी त्रुटि: <ph name="ERROR_LINE" /></translation>
 <translation id="5846807460505171493">एप र तिनका अद्यावधिकहरू स्थापना गर्नुहोस्। जारी राखेर, तपाईं यस यन्त्रले Google, तपाईंका सेवा प्रदायक र तपाईंको यन्त्रका उत्पादकहरूका एप र तिनका अद्यावधिकहरू स्वत: डाउनलोड गरी स्थापना गर्न पनि सक्छ तथा यो काममा सम्भवतः मोबाइल इन्टरनेटको प्रयोग पनि हुन सक्छ भन्ने कुरामा सहमति जनाउनुहुन्छ। यीमध्ये केही एपहरूले एपभित्र किनमेल गर्ने सुविधा प्रदान गर्न सक्छन्।</translation>
 <translation id="5849212445710944278">पहिल्यै थपिएको छ</translation>
diff --git a/chrome/app/resources/generated_resources_sq.xtb b/chrome/app/resources/generated_resources_sq.xtb
index d221dc2..33d961e 100644
--- a/chrome/app/resources/generated_resources_sq.xtb
+++ b/chrome/app/resources/generated_resources_sq.xtb
@@ -2182,6 +2182,7 @@
 <translation id="3732857534841813090">Informacioni i lidhur i "Asistentit të Google"</translation>
 <translation id="3733127536501031542">Server SSL me rritje</translation>
 <translation id="3735740477244556633">Rendit sipas</translation>
+<translation id="3738213647660363521">Personalizo ngjyrën e kursorit</translation>
 <translation id="3738924763801731196"><ph name="OID" />:</translation>
 <translation id="3739254215541673094">Të hapet <ph name="APPLICATION" />?</translation>
 <translation id="3742055079367172538">Pamja e ekranit u mor</translation>
@@ -3294,6 +3295,7 @@
 <translation id="52232769093306234">Paketimi dështoi.</translation>
 <translation id="5225324770654022472">Shfaq shkurtoren e aplikacioneve</translation>
 <translation id="5227679487546032910">Avatari i parazgjedhur gurkali</translation>
+<translation id="5228088094491423618">Titra në çast</translation>
 <translation id="5228579091201413441">Aktivizo sinkronizimin</translation>
 <translation id="5229189185761556138">Menaxho metodat e hyrjes</translation>
 <translation id="5230516054153933099">Dritare</translation>
@@ -6346,6 +6348,7 @@
 <translation id="9121814364785106365">Hap si skedë të gozhduar</translation>
 <translation id="9122176249172999202"><ph name="IDS_SHORT_PRODUCT_NAME" /> është vendosur në pauzë</translation>
 <translation id="9124003689441359348">Fjalëkalimet e ruajtura do të shfaqen këtu</translation>
+<translation id="9126149354162942022">Ngjyra e kursorit</translation>
 <translation id="9128317794749765148">Konfigurimi nuk mund të përfundonte</translation>
 <translation id="9128870381267983090">Lidhu me rrjetin</translation>
 <translation id="9130015405878219958">U fut modalitet i pavlefshëm.</translation>
diff --git a/chrome/app/resources/generated_resources_sw.xtb b/chrome/app/resources/generated_resources_sw.xtb
index ab383ec..d15725a 100644
--- a/chrome/app/resources/generated_resources_sw.xtb
+++ b/chrome/app/resources/generated_resources_sw.xtb
@@ -2182,6 +2182,7 @@
 <translation id="3732857534841813090">Maelezo yanayohusiana ya programu ya Mratibu wa Google</translation>
 <translation id="3733127536501031542">Seva ya SSL iliyo na Upandishaji</translation>
 <translation id="3735740477244556633">Panga kwa</translation>
+<translation id="3738213647660363521">Rangi ya kiteuzi maalum</translation>
 <translation id="3738924763801731196"><ph name="OID" />:</translation>
 <translation id="3739254215541673094">Ungependa kufungua <ph name="APPLICATION" />?</translation>
 <translation id="3742055079367172538">Picha ya skrini imepigwa</translation>
@@ -3292,6 +3293,7 @@
 <translation id="52232769093306234">Imeshindwa kupakia faili.</translation>
 <translation id="5225324770654022472">Onyesha mkato wa programu</translation>
 <translation id="5227679487546032910">Ishara chaguomsingi ya kijani kiwiti</translation>
+<translation id="5228088094491423618">Manukuu Papo Hapo</translation>
 <translation id="5228579091201413441">Washa usawazishaji</translation>
 <translation id="5229189185761556138">Dhibiti mbinu za kuingiza data</translation>
 <translation id="5230516054153933099">Dirisha</translation>
@@ -6348,6 +6350,7 @@
 <translation id="9121814364785106365">Fungua kama kichupo kilichobanwa</translation>
 <translation id="9122176249172999202"><ph name="IDS_SHORT_PRODUCT_NAME" /> imesimamishwa</translation>
 <translation id="9124003689441359348">Manenosiri yaliyohifadhiwa yataonekana hapa</translation>
+<translation id="9126149354162942022">Rangi ya kiteuzi</translation>
 <translation id="9128317794749765148">Imeshindwa kukamilisha shughuli ya kusakinisha</translation>
 <translation id="9128870381267983090">Unganisha kwenye mtandao</translation>
 <translation id="9130015405878219958">Modi batili imeingizwa.</translation>
diff --git a/chrome/app/resources/generated_resources_th.xtb b/chrome/app/resources/generated_resources_th.xtb
index e6a18bc..64bd4979 100644
--- a/chrome/app/resources/generated_resources_th.xtb
+++ b/chrome/app/resources/generated_resources_th.xtb
@@ -2185,6 +2185,7 @@
 <translation id="3732857534841813090">ข้อมูลที่เกี่ยวข้องของ Google Assistant</translation>
 <translation id="3733127536501031542">เซิร์ฟเวอร์ SSL ที่มีการยกระดับความปลอดภัย</translation>
 <translation id="3735740477244556633">จัดเรียงตาม</translation>
+<translation id="3738213647660363521">สีเคอร์เซอร์ที่กำหนดเอง</translation>
 <translation id="3738924763801731196"><ph name="OID" />:</translation>
 <translation id="3739254215541673094">เปิด <ph name="APPLICATION" /> ไหม</translation>
 <translation id="3742055079367172538">ภาพหน้าจอที่บันทึก</translation>
@@ -3297,6 +3298,7 @@
 <translation id="52232769093306234">การบรรจุล้มเหลว</translation>
 <translation id="5225324770654022472">แสดงทางลัดแอป</translation>
 <translation id="5227679487546032910">รูปโปรไฟล์เริ่มต้นสีน้ำเงินอมเขียว</translation>
+<translation id="5228088094491423618">คำบรรยายสด</translation>
 <translation id="5228579091201413441">เปิดใช้การซิงค์</translation>
 <translation id="5229189185761556138">จัดการวิธีป้อนข้อมูล</translation>
 <translation id="5230516054153933099">หน้าต่าง</translation>
@@ -6351,6 +6353,7 @@
 <translation id="9121814364785106365">เปิดเป็นแท็บที่ปักหมุดไว้</translation>
 <translation id="9122176249172999202"><ph name="IDS_SHORT_PRODUCT_NAME" /> หยุดชั่วคราว</translation>
 <translation id="9124003689441359348">รหัสผ่านที่บันทึกไว้จะแสดงที่นี่</translation>
+<translation id="9126149354162942022">สีของเคอร์เซอร์</translation>
 <translation id="9128317794749765148">ตั้งค่าไม่สำเร็จ</translation>
 <translation id="9128870381267983090">เชื่อมต่อกับเครือข่าย</translation>
 <translation id="9130015405878219958">โหมดที่ป้อนไม่ถูกต้อง</translation>
diff --git a/chrome/app/resources/generated_resources_zh-TW.xtb b/chrome/app/resources/generated_resources_zh-TW.xtb
index 189a4d4..6872b84 100644
--- a/chrome/app/resources/generated_resources_zh-TW.xtb
+++ b/chrome/app/resources/generated_resources_zh-TW.xtb
@@ -2124,6 +2124,7 @@
 <translation id="3677106374019847299">輸入自訂供應商</translation>
 <translation id="3677657024345889897">最小</translation>
 <translation id="3677911431265050325">切換為行動版網站</translation>
+<translation id="3677959414150797585">包括應用程式、網頁等。只有當你選擇提供使用資料時,系統才會傳送統計資料以改善建議項目。</translation>
 <translation id="3678156199662914018">擴充功能:<ph name="EXTENSION_NAME" /></translation>
 <translation id="3680683624079082902">文字轉語音的聲音</translation>
 <translation id="3681311097828166361">感謝你提供意見!你目前處於離線狀態,重新上線後系統就會傳送你的意見回饋報告。</translation>
@@ -3775,6 +3776,7 @@
 <translation id="5835486486592033703"><ph name="WINDOW_TITLE" /> - 攝影機或麥克風錄影/錄音中</translation>
 <translation id="5841270259333717135">設定乙太網路</translation>
 <translation id="5842497610951477805">啟用藍牙</translation>
+<translation id="5844574845205796324">建議新的探索內容</translation>
 <translation id="5846200638699387931">關聯語法錯誤:<ph name="ERROR_LINE" /></translation>
 <translation id="5846807460505171493">安裝更新內容和應用程式。如果您選擇繼續,即表示您允許這部裝置自動下載及安裝來自 Google、您的電信業者和裝置製造商的更新內容和應用程式,且可能會使用行動數據進行下載。部分應用程式可能會提供內購項目。</translation>
 <translation id="5849212445710944278">已加入過了</translation>
diff --git a/chrome/app/resources/generated_resources_zu.xtb b/chrome/app/resources/generated_resources_zu.xtb
index 43504f1..fa98557 100644
--- a/chrome/app/resources/generated_resources_zu.xtb
+++ b/chrome/app/resources/generated_resources_zu.xtb
@@ -2183,6 +2183,7 @@
 <translation id="3732857534841813090">Ulwazi oluhambisana nomsizi we-Google</translation>
 <translation id="3733127536501031542">Iseva ye-SSL enokunyukela phezulu</translation>
 <translation id="3735740477244556633">Hlunga nge-</translation>
+<translation id="3738213647660363521">Umbala we-cursor ongokwezifiso</translation>
 <translation id="3738924763801731196"><ph name="OID" />:</translation>
 <translation id="3739254215541673094">Vula i-<ph name="APPLICATION" />?</translation>
 <translation id="3742055079367172538">Kuthathwe isithombe-skrini</translation>
@@ -3294,6 +3295,7 @@
 <translation id="52232769093306234">Ukupakisha kuhlulekile.</translation>
 <translation id="5225324770654022472">Bonisa isinqamuleli sohlelo lokusebenza</translation>
 <translation id="5227679487546032910">Isithombe esizenzakalelayo esisaluhlaza</translation>
+<translation id="5228088094491423618">Amagama-ncazo abukhoma</translation>
 <translation id="5228579091201413441">Nika amandla ukuvumelanisa</translation>
 <translation id="5229189185761556138">Phatha izindlela zokokufaka</translation>
 <translation id="5230516054153933099">Iwindi</translation>
@@ -6350,6 +6352,7 @@
 <translation id="9121814364785106365">Vula njengethebhu ephiniwe</translation>
 <translation id="9122176249172999202">I-<ph name="IDS_SHORT_PRODUCT_NAME" /> iphunyuziwe</translation>
 <translation id="9124003689441359348">Amaphasiwedi alondoloziwe azovela lapha</translation>
+<translation id="9126149354162942022">Umbala we-cursor</translation>
 <translation id="9128317794749765148">Ukusetha akukwazanga ukuqedelelwa</translation>
 <translation id="9128870381267983090">Xhuma kunethiwekhi</translation>
 <translation id="9130015405878219958">Kufakwe imodi engavumelekile.</translation>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index d3bfb88..202d0234 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -503,13 +503,17 @@
   <message name="IDS_SETTINGS_PASSWORDS_MANAGE_PASSWORDS" desc="Shown in the passwords section of settings. Descriptive text to inform that passwords can be accessed online. Has a link.">
     View and manage saved passwords in your <ph name="BEGIN_LINK">&lt;a is="action-link" href="$1" target="_blank"&gt;</ph>Google Account<ph name="END_LINK">&lt;/a&gt;</ph>
   </message>
-  <!-- TODO(crbug.com/1062344): Make it translateable and use definitive label once final mocks are available. -->
-  <message translateable="false" name="IDS_SETTINGS_PASSWORDS_OPT_IN_ACCOUNT_STORAGE_LABEL" desc="Label for a button in the passwords section of settings triggering opt in to passwords account storage.">
-    Opt-in to account storage
+  <message name="IDS_SETTINGS_PASSWORDS_OPT_IN_ACCOUNT_STORAGE_BODY" desc="Description before a button in the passwords section of settings which triggers opt in to passwords account storage.">
+    You can also show passwords from your Google Account here
   </message>
-  <!-- TODO(crbug.com/1062344): Make it translateable and use definitive label once final mocks are available. -->
-  <message translateable="false" name="IDS_SETTINGS_PASSWORDS_OPT_OUT_ACCOUNT_STORAGE_LABEL" desc="Label for a button in the passwords section of settings triggering opt out of passwords account storage.">
-    Opt-out of account storage
+  <message name="IDS_SETTINGS_PASSWORDS_OPT_IN_ACCOUNT_STORAGE_LABEL" desc="Label for a button in the passwords section of settings which triggers opt in to passwords account storage.">
+    Show
+  </message>
+  <message name="IDS_SETTINGS_PASSWORDS_OPT_OUT_ACCOUNT_STORAGE_BODY" desc="Description before a button in the passwords section of settings which triggers opt out of passwords account storage.">
+    Showing passwords from your Google Account
+  </message>
+  <message name="IDS_SETTINGS_PASSWORDS_OPT_OUT_ACCOUNT_STORAGE_LABEL" desc="Label for a button in the passwords section of settings which triggers opt out of passwords account storage.">
+    Remove from device
   </message>
   <message name="IDS_SETTINGS_PASSWORDS_EXPORT_MENU_ITEM" desc="A menu item in the More Actions menu above the password list in Chrome's settings. Selecting this action will open a dialog, through which the user can export their passwords outside of Chrome.">
     Export passwords...
@@ -1190,6 +1194,13 @@
   <message name="IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BUTTON_ARIA_LABEL" desc="Accessibility text for the button that allows users to review their extensions settings.">
     Review extensions
   </message>
+  <message name="IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_PRIMARY_LABEL" desc="'Unwanted software protection' is an element in safety check that finds harmful software installed on the computer and allows users to remove it.">
+    Unwanted software protection
+  </message>
+  <message name="IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_BUTTON_ARIA_LABEL" desc="Accessiblity text for the button that allows users to review and remove harmful software found on their computer.">
+    Review unwanted software
+  </message>
+
   <message name="IDS_SETTINGS_NETWORK_PREDICTION_ENABLED_LABEL" desc="In the advanced options tab, the text next to the checkbox that enables prediction of network actions.  Actions include browser-initiated DNS prefetching, TCP and SSL preconnection, and prerendering of webpages.">
     Preload pages for faster browsing and searching
   </message>
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_OPT_IN_ACCOUNT_STORAGE_BODY.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_OPT_IN_ACCOUNT_STORAGE_BODY.png.sha1
new file mode 100644
index 0000000..0b8ea92
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_OPT_IN_ACCOUNT_STORAGE_BODY.png.sha1
@@ -0,0 +1 @@
+f57e988cf79c532860723926e3e7bb50ede2d5ef
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_OPT_IN_ACCOUNT_STORAGE_LABEL.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_OPT_IN_ACCOUNT_STORAGE_LABEL.png.sha1
new file mode 100644
index 0000000..0b8ea92
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_OPT_IN_ACCOUNT_STORAGE_LABEL.png.sha1
@@ -0,0 +1 @@
+f57e988cf79c532860723926e3e7bb50ede2d5ef
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_OPT_OUT_ACCOUNT_STORAGE_BODY.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_OPT_OUT_ACCOUNT_STORAGE_BODY.png.sha1
new file mode 100644
index 0000000..7b75692e
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_OPT_OUT_ACCOUNT_STORAGE_BODY.png.sha1
@@ -0,0 +1 @@
+73b61ea766f0d8426d1a72c4dfaa81d8c19a582f
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_OPT_OUT_ACCOUNT_STORAGE_LABEL.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_OPT_OUT_ACCOUNT_STORAGE_LABEL.png.sha1
new file mode 100644
index 0000000..7b75692e
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORDS_OPT_OUT_ACCOUNT_STORAGE_LABEL.png.sha1
@@ -0,0 +1 @@
+73b61ea766f0d8426d1a72c4dfaa81d8c19a582f
\ No newline at end of file
diff --git a/chrome/app/xr_consent_ui_strings.grdp b/chrome/app/xr_consent_ui_strings.grdp
deleted file mode 100644
index 662ff0d5..0000000
--- a/chrome/app/xr_consent_ui_strings.grdp
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2019 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-<!-- XR specific strings (included from generated_resources.grd and android_chrome_strings.grd). -->
-<!-- These strings are used in the consent flow dialog. -->
-<grit-part>
-  <!-- XR consent dialog. -->
-  <message name="IDS_XR_CONSENT_DIALOG_TITLE" desc="Title of the user consent dialog displayed before allowing a website to start a VR presentation">
-    Enter VR from <ph name="DOMAIN">$1<ex>example.com</ex></ph>?
-  </message>
-  <message name="IDS_XR_CONSENT_DIALOG_DESCRIPTION_DEFAULT" desc="This is the header for a bulleted list of potential concerns that we want to ensure the user is aware of before entering VR. This header and the appended items of the bulleted list make up the body of the user consent dialog displayed before a website may start a VR presentation.">
-    While you're in VR, this site may be able to learn about:
-  </message>
-  <message name="IDS_XR_CONSENT_DIALOG_DESCRIPTION_PHYSICAL_FEATURES" desc="Item for the bulleted list of potential concerns in the consent dialog indicating that physical features may be exposed.">
-    your physical features, such as height
-  </message>
-  <message name="IDS_XR_CONSENT_DIALOG_DESCRIPTION_FLOOR_PLAN" desc="Item for the bulleted list of potential concerns in the consent dialog indicating that phyiscal features may be exposed.">
-    the layout of your room
-  </message>
-  <message name="IDS_XR_CONSENT_DIALOG_BUTTON_ALLOW_AND_ENTER_VR" desc="Text on the button of a user consent dialog which allows a website to start a VR presentation">
-    Enter VR
-  </message>
-</grit-part>
diff --git a/chrome/app/xr_consent_ui_strings_grdp/IDS_XR_CONSENT_DIALOG_BUTTON_ALLOW_AND_ENTER_VR.png.sha1 b/chrome/app/xr_consent_ui_strings_grdp/IDS_XR_CONSENT_DIALOG_BUTTON_ALLOW_AND_ENTER_VR.png.sha1
deleted file mode 100644
index 1df7689..0000000
--- a/chrome/app/xr_consent_ui_strings_grdp/IDS_XR_CONSENT_DIALOG_BUTTON_ALLOW_AND_ENTER_VR.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-a39ab5f7c790fdf648f0ec58067ecf21896da0e2
\ No newline at end of file
diff --git a/chrome/app/xr_consent_ui_strings_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_DEFAULT.png.sha1 b/chrome/app/xr_consent_ui_strings_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_DEFAULT.png.sha1
deleted file mode 100644
index 021307ae..0000000
--- a/chrome/app/xr_consent_ui_strings_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_DEFAULT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-e6d8bdaf00353e40e2a7210ea0b4e75b6985b313
\ No newline at end of file
diff --git a/chrome/app/xr_consent_ui_strings_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_FLOOR_PLAN.png.sha1 b/chrome/app/xr_consent_ui_strings_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_FLOOR_PLAN.png.sha1
deleted file mode 100644
index e3266c1..0000000
--- a/chrome/app/xr_consent_ui_strings_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_FLOOR_PLAN.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-b187c7e1cbe99db2f62bf47bd0b4edc842612fb7
\ No newline at end of file
diff --git a/chrome/app/xr_consent_ui_strings_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_PHYSICAL_FEATURES.png.sha1 b/chrome/app/xr_consent_ui_strings_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_PHYSICAL_FEATURES.png.sha1
deleted file mode 100644
index f1e6e55..0000000
--- a/chrome/app/xr_consent_ui_strings_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_PHYSICAL_FEATURES.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-3ca99892b388f5a40946d0ece68479074c289f23
\ No newline at end of file
diff --git a/chrome/app/xr_consent_ui_strings_grdp/IDS_XR_CONSENT_DIALOG_TITLE.png.sha1 b/chrome/app/xr_consent_ui_strings_grdp/IDS_XR_CONSENT_DIALOG_TITLE.png.sha1
deleted file mode 100644
index f818cca..0000000
--- a/chrome/app/xr_consent_ui_strings_grdp/IDS_XR_CONSENT_DIALOG_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-24fc61598a47f3b74fbe4f97beb27602e4ebf681
\ No newline at end of file
diff --git a/chrome/app/xr_consent_ui_strings_grdp/OWNERS b/chrome/app/xr_consent_ui_strings_grdp/OWNERS
deleted file mode 100644
index cf26380..0000000
--- a/chrome/app/xr_consent_ui_strings_grdp/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://chrome/browser/vr/OWNERS
diff --git a/chrome/app/xr_consent_ui_strings_grdp/README.md b/chrome/app/xr_consent_ui_strings_grdp/README.md
deleted file mode 100644
index f013bb5..0000000
--- a/chrome/app/xr_consent_ui_strings_grdp/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-This directory of image SHA-1 hashes is used to improve translations of UI
-strings through context images for translators.
-
-See also: [Chrome Translation Screenshots - Instructions & FAQ
-](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index c0da92e..fcc1c28 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -400,14 +400,13 @@
     "download/download_core_service_impl.cc",
     "download/download_core_service_impl.h",
     "download/download_crx_util_android.cc",
+    "download/download_dialog_types.h",
     "download/download_file_picker.cc",
     "download/download_file_picker.h",
     "download/download_history.cc",
     "download/download_history.h",
     "download/download_item_model.cc",
     "download/download_item_model.h",
-    "download/download_location_dialog_result.h",
-    "download/download_location_dialog_type.h",
     "download/download_manager_utils.cc",
     "download/download_manager_utils.h",
     "download/download_offline_content_provider.cc",
@@ -2092,6 +2091,7 @@
     "//components/history/content/browser",
     "//components/history/core/browser",
     "//components/history/core/common",
+    "//components/infobars/content",
     "//components/infobars/core",
     "//components/invalidation/impl",
     "//components/javascript_dialogs",
@@ -2839,9 +2839,8 @@
       "download/android/download_controller.h",
       "download/android/download_controller_base.cc",
       "download/android/download_controller_base.h",
+      "download/android/download_dialog_bridge.cc",
       "download/android/download_dialog_bridge.h",
-      "download/android/download_dialog_bridge_impl.cc",
-      "download/android/download_dialog_bridge_impl.h",
       "download/android/download_manager_bridge.cc",
       "download/android/download_manager_bridge.h",
       "download/android/download_manager_service.cc",
@@ -2879,6 +2878,10 @@
       "installable/installable_ambient_badge_infobar_delegate.cc",
       "installable/installed_webapp_bridge.cc",
       "installable/installed_webapp_bridge.h",
+      "installable/installed_webapp_geolocation_bridge.cc",
+      "installable/installed_webapp_geolocation_bridge.h",
+      "installable/installed_webapp_geolocation_context.cc",
+      "installable/installed_webapp_geolocation_context.h",
       "installable/installed_webapp_provider.cc",
       "installable/installed_webapp_provider.h",
       "lifetime/application_lifetime_android.cc",
@@ -3039,6 +3042,7 @@
       "//chrome/browser/offline_pages/prefetch/notifications",
       "//chrome/browser/optimization_guide/android:jni_headers",
       "//chrome/browser/payments/android:jni_headers",
+      "//chrome/browser/safety_check/android",
       "//chrome/browser/share",
       "//chrome/browser/updates",
       "//chrome/common:non_code_constants",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 360a387d..0365023 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -131,6 +131,7 @@
   "+components/history/core/common",
   "+components/history/core/test",
   "+components/image_fetcher/core",
+  "+components/infobars/content",
   "+components/infobars/core",
   "+components/invalidation/impl",
   "+components/invalidation/public",
@@ -374,9 +375,7 @@
   # Code under //ash should be accessed via its public API. See //ash/README.md.
   "-ash",
   "+ash/public",
-  "+ash/keyboard/ui/public",
   "+ash/keyboard/ui/grit",
-  "+ash/keyboard/ui/public",
   "+ash/keyboard/ui/resources",
   "+ash/components/shortcut_viewer",
 
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index ce415b7e..dacfc9fb 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -5671,6 +5671,13 @@
      FEATURE_VALUE_TYPE(
          autofill::features::kAutofillEnableCardNicknameUpstream)},
 
+#if defined(OS_WIN)
+    {"safety-check-chrome-cleaner-child",
+     flag_descriptions::kSafetyCheckChromeCleanerChildName,
+     flag_descriptions::kSafetyCheckChromeCleanerChildDescription, kOsWin,
+     FEATURE_VALUE_TYPE(features::kSafetyCheckChromeCleanerChild)},
+#endif  // !defined(OS_WIN)
+
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
     // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/android/autofill_assistant/assistant_generic_ui_delegate.cc b/chrome/browser/android/autofill_assistant/assistant_generic_ui_delegate.cc
index caedf13..3f80cd06 100644
--- a/chrome/browser/android/autofill_assistant/assistant_generic_ui_delegate.cc
+++ b/chrome/browser/android/autofill_assistant/assistant_generic_ui_delegate.cc
@@ -74,4 +74,14 @@
   return java_assistant_generic_ui_delegate_;
 }
 
+void AssistantGenericUiDelegate::OnViewContainerCleared(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& jcaller,
+    const base::android::JavaParamRef<jstring>& jview_identifier) {
+  ui_controller_->OnViewEvent(
+      {EventProto::kOnViewContainerCleared,
+       ui_controller_android_utils::SafeConvertJavaStringToNative(
+           env, jview_identifier)});
+}
+
 }  // namespace autofill_assistant
diff --git a/chrome/browser/android/autofill_assistant/assistant_generic_ui_delegate.h b/chrome/browser/android/autofill_assistant/assistant_generic_ui_delegate.h
index 73a143bf..d499803e 100644
--- a/chrome/browser/android/autofill_assistant/assistant_generic_ui_delegate.h
+++ b/chrome/browser/android/autofill_assistant/assistant_generic_ui_delegate.h
@@ -16,31 +16,31 @@
   explicit AssistantGenericUiDelegate(UiControllerAndroid* ui_controller);
   ~AssistantGenericUiDelegate();
 
-  // A view was clicked in the UI. |jview_identifier| is the corresponding view
-  // identifier.
   void OnViewClicked(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& jcaller,
       const base::android::JavaParamRef<jstring>& jview_identifier);
 
-  // A value was changed on the Java side. Native should update the model.
   void OnValueChanged(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& jcaller,
       const base::android::JavaParamRef<jstring>& jmodel_identifier,
       const base::android::JavaParamRef<jobject>& jvalue);
 
-  // A text link was clicked.
   void OnTextLinkClicked(JNIEnv* env,
                          const base::android::JavaParamRef<jobject>& jcaller,
                          jint jlink);
 
-  // A generic popup was dismissed.
   void OnGenericPopupDismissed(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& jcaller,
       const base::android::JavaParamRef<jstring>& jpopup_identifier);
 
+  void OnViewContainerCleared(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& jcaller,
+      const base::android::JavaParamRef<jstring>& jview_identifier);
+
   base::android::ScopedJavaGlobalRef<jobject> GetJavaObject();
 
  private:
diff --git a/chrome/browser/android/autofill_assistant/generic_ui_events_android.cc b/chrome/browser/android/autofill_assistant/generic_ui_events_android.cc
index 485a9b7..a745dd0 100644
--- a/chrome/browser/android/autofill_assistant/generic_ui_events_android.cc
+++ b/chrome/browser/android/autofill_assistant/generic_ui_events_android.cc
@@ -48,7 +48,8 @@
       case EventProto::kOnUserActionCalled:
       case EventProto::kOnTextLinkClicked:
       case EventProto::kOnPopupDismissed:
-        // Skip events not related to java views.
+      case EventProto::kOnViewContainerCleared:
+        // Skip events that do not require registering java-side listeners.
         break;
       case EventProto::KIND_NOT_SET:
         VLOG(1)
diff --git a/chrome/browser/android/autofill_assistant/generic_ui_interactions_android.cc b/chrome/browser/android/autofill_assistant/generic_ui_interactions_android.cc
index 5cbc207a..d49095f 100644
--- a/chrome/browser/android/autofill_assistant/generic_ui_interactions_android.cc
+++ b/chrome/browser/android/autofill_assistant/generic_ui_interactions_android.cc
@@ -355,5 +355,48 @@
   }
 }
 
+void ClearViewContainer(
+    const std::string& view_identifier,
+    std::map<std::string, base::android::ScopedJavaGlobalRef<jobject>>* views,
+    base::android::ScopedJavaGlobalRef<jobject> jdelegate) {
+  auto jview = views->find(view_identifier);
+  if (jview == views->end()) {
+    DVLOG(2) << "Failed to clear view container " << view_identifier
+             << ": view not found";
+    return;
+  }
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  if (!Java_AssistantViewInteractions_clearViewContainer(
+          env, jview->second,
+          base::android::ConvertUTF8ToJavaString(env, view_identifier),
+          jdelegate)) {
+    DVLOG(2) << "Failed to clear view container " << view_identifier
+             << ": JNI call failed";
+    return;
+  }
+}
+
+bool AttachViewToParent(
+    base::android::ScopedJavaGlobalRef<jobject> jview,
+    const std::string& parent_view_identifier,
+    std::map<std::string, base::android::ScopedJavaGlobalRef<jobject>>* views) {
+  auto jparent_view = views->find(parent_view_identifier);
+  if (jparent_view == views->end()) {
+    DVLOG(2) << "Failed to attach view to " << parent_view_identifier
+             << ": parent not found";
+    return false;
+  }
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  if (!Java_AssistantViewInteractions_attachViewToParent(
+          env, jparent_view->second, jview)) {
+    DVLOG(2) << "Failed to attach view to " << parent_view_identifier
+             << ": JNI call failed";
+    return false;
+  }
+  return true;
+}
+
 }  // namespace android_interactions
 }  // namespace autofill_assistant
diff --git a/chrome/browser/android/autofill_assistant/generic_ui_interactions_android.h b/chrome/browser/android/autofill_assistant/generic_ui_interactions_android.h
index 63d774b..aeafe0f3 100644
--- a/chrome/browser/android/autofill_assistant/generic_ui_interactions_android.h
+++ b/chrome/browser/android/autofill_assistant/generic_ui_interactions_android.h
@@ -93,6 +93,18 @@
     const std::string& model_identifier,
     std::map<std::string, base::android::ScopedJavaGlobalRef<jobject>>* views);
 
+// Removes all child views from |view_identifier|.
+void ClearViewContainer(
+    const std::string& view_identifier,
+    std::map<std::string, base::android::ScopedJavaGlobalRef<jobject>>* views,
+    base::android::ScopedJavaGlobalRef<jobject> jdelegate);
+
+// Attaches |jview| to a parent view.
+bool AttachViewToParent(
+    base::android::ScopedJavaGlobalRef<jobject> jview,
+    const std::string& parent_view_identifier,
+    std::map<std::string, base::android::ScopedJavaGlobalRef<jobject>>* views);
+
 }  // namespace android_interactions
 }  // namespace autofill_assistant
 
diff --git a/chrome/browser/android/autofill_assistant/interaction_handler_android.cc b/chrome/browser/android/autofill_assistant/interaction_handler_android.cc
index 696a0d9..c60af1e 100644
--- a/chrome/browser/android/autofill_assistant/interaction_handler_android.cc
+++ b/chrome/browser/android/autofill_assistant/interaction_handler_android.cc
@@ -68,6 +68,15 @@
       }
       return base::Optional<EventHandler::EventKey>(
           {proto.kind_case(), proto.on_popup_dismissed().popup_identifier()});
+    case EventProto::kOnViewContainerCleared:
+      if (proto.on_view_container_cleared().view_identifier().empty()) {
+        VLOG(1) << "Invalid OnViewContainerClearedProto: no view_identifier "
+                   "specified";
+        return base::nullopt;
+      }
+      return base::Optional<EventHandler::EventKey>(
+          {proto.kind_case(),
+           proto.on_view_container_cleared().view_identifier()});
     case EventProto::KIND_NOT_SET:
       VLOG(1) << "Error creating event: kind not set";
       return base::nullopt;
@@ -313,6 +322,24 @@
       return base::Optional<InteractionCallback>(base::BindRepeating(
           &InteractionHandlerAndroid::CreateAndShowGenericPopup, GetWeakPtr(),
           proto.show_generic_popup()));
+    case CallbackProto::kCreateNestedUi:
+      if (proto.create_nested_ui().generic_ui_identifier().empty()) {
+        VLOG(1) << "Error creating CreateNestedGenericUi interaction: "
+                   "generic_ui_identifier not set";
+        return base::nullopt;
+      }
+      return base::Optional<InteractionCallback>(base::BindRepeating(
+          &InteractionHandlerAndroid::CreateAndAttachNestedGenericUi,
+          GetWeakPtr(), proto.create_nested_ui()));
+    case CallbackProto::kClearViewContainer:
+      if (proto.clear_view_container().view_identifier().empty()) {
+        VLOG(1) << "Error creating ClearViewContainer interaction: "
+                   "view_identifier not set";
+        return base::nullopt;
+      }
+      return base::Optional<InteractionCallback>(base::BindRepeating(
+          &android_interactions::ClearViewContainer,
+          proto.clear_view_container().view_identifier(), views_, jdelegate_));
     case CallbackProto::KIND_NOT_SET:
       VLOG(1) << "Error creating interaction: kind not set";
       return base::nullopt;
@@ -329,24 +356,50 @@
 const GenericUiControllerAndroid* InteractionHandlerAndroid::CreateNestedUi(
     const GenericUserInterfaceProto& proto,
     const std::string& identifier) {
+  if (nested_ui_controllers_.find(identifier) != nested_ui_controllers_.end()) {
+    VLOG(2) << "Error creating nested UI: " << identifier
+            << " already exixsts (did you forget to clear the previous "
+               "instance with ClearViewContainerProto?)";
+    return nullptr;
+  }
   auto nested_ui = GenericUiControllerAndroid::CreateFromProto(
       proto, jcontext_, jdelegate_, event_handler_, user_model_,
       basic_interactions_);
   const auto* nested_ui_ptr = nested_ui.get();
   if (nested_ui) {
-    DCHECK(nested_ui_controllers_.find(identifier) ==
-           nested_ui_controllers_.end());
     nested_ui_controllers_.emplace(identifier, std::move(nested_ui));
+  } else {
+    VLOG(2) << "Error creating nested UI " << identifier
+            << ": view inflation failed";
   }
   return nested_ui_ptr;
 }
 
+void InteractionHandlerAndroid::CreateAndAttachNestedGenericUi(
+    const CreateNestedGenericUiProto& proto) {
+  auto* nested_ui =
+      CreateNestedUi(proto.generic_ui(), proto.generic_ui_identifier());
+  if (!nested_ui) {
+    return;
+  }
+
+  if (!android_interactions::AttachViewToParent(
+          nested_ui->GetRootView(), proto.parent_view_identifier(), views_)) {
+    DeleteNestedUi(proto.generic_ui_identifier());
+    return;
+  }
+
+  AddInteraction(
+      {EventProto::kOnViewContainerCleared, proto.parent_view_identifier()},
+      base::BindRepeating(&InteractionHandlerAndroid::DeleteNestedUi,
+                          GetWeakPtr(), proto.generic_ui_identifier()));
+}
+
 void InteractionHandlerAndroid::CreateAndShowGenericPopup(
     const ShowGenericUiPopupProto& proto) {
   auto* nested_ui =
       CreateNestedUi(proto.generic_ui(), proto.popup_identifier());
   if (!nested_ui) {
-    DVLOG(2) << "Error showing popup: error creating generic UI";
     return;
   }
   AddInteraction({EventProto::kOnPopupDismissed, proto.popup_identifier()},
diff --git a/chrome/browser/android/autofill_assistant/interaction_handler_android.h b/chrome/browser/android/autofill_assistant/interaction_handler_android.h
index b4c1197..765c901 100644
--- a/chrome/browser/android/autofill_assistant/interaction_handler_android.h
+++ b/chrome/browser/android/autofill_assistant/interaction_handler_android.h
@@ -91,6 +91,7 @@
       const GenericUserInterfaceProto& proto,
       const std::string& identifier);
 
+  void CreateAndAttachNestedGenericUi(const CreateNestedGenericUiProto& proto);
   void CreateAndShowGenericPopup(const ShowGenericUiPopupProto& proto);
 
   // Maps event keys to the corresponding list of callbacks to execute.
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.cc b/chrome/browser/android/tab_web_contents_delegate_android.cc
index ad17313..7f11302 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.cc
+++ b/chrome/browser/android/tab_web_contents_delegate_android.cc
@@ -30,6 +30,8 @@
 #include "chrome/browser/flags/android/chrome_feature_list.h"
 #include "chrome/browser/history/history_tab_helper.h"
 #include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/installable/installed_webapp_bridge.h"
+#include "chrome/browser/installable/installed_webapp_geolocation_context.h"
 #include "chrome/browser/media/protected_media_identifier_permission_context.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
@@ -500,6 +502,18 @@
                         /* did_finish_load */ !is_loading);
 }
 
+device::mojom::GeolocationContext*
+TabWebContentsDelegateAndroid::GetInstalledWebappGeolocationContext() {
+  if (!IsInstalledWebappDelegateGeolocation())
+    return nullptr;
+
+  if (!installed_webapp_geolocation_context_) {
+    installed_webapp_geolocation_context_ =
+        std::make_unique<InstalledWebappGeolocationContext>();
+  }
+  return installed_webapp_geolocation_context_.get();
+}
+
 #if BUILDFLAG(ENABLE_PRINTING)
 void TabWebContentsDelegateAndroid::PrintCrossProcessSubframe(
     content::WebContents* web_contents,
@@ -608,6 +622,16 @@
   return Java_TabWebContentsDelegateAndroidImpl_isCustomTab(env, obj);
 }
 
+bool TabWebContentsDelegateAndroid::IsInstalledWebappDelegateGeolocation()
+    const {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
+  if (obj.is_null())
+    return false;
+  return Java_TabWebContentsDelegateAndroidImpl_isInstalledWebappDelegateGeolocation(
+      env, obj);
+}
+
 }  // namespace android
 
 void JNI_TabWebContentsDelegateAndroidImpl_OnRendererUnresponsive(
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.h b/chrome/browser/android/tab_web_contents_delegate_android.h
index ad0ebee..be558a5 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.h
+++ b/chrome/browser/android/tab_web_contents_delegate_android.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_ANDROID_TAB_WEB_CONTENTS_DELEGATE_ANDROID_H_
 #define CHROME_BROWSER_ANDROID_TAB_WEB_CONTENTS_DELEGATE_ANDROID_H_
 
+#include <memory>
+
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
@@ -118,6 +120,8 @@
   std::unique_ptr<content::WebContents> ActivatePortalWebContents(
       content::WebContents* predecessor_contents,
       std::unique_ptr<content::WebContents> portal_contents) override;
+  device::mojom::GeolocationContext* GetInstalledWebappGeolocationContext()
+      override;
 
 #if BUILDFLAG(ENABLE_PRINTING)
   void PrintCrossProcessSubframe(
@@ -149,8 +153,12 @@
   // might change over the lifetime of the tab.
   bool IsCustomTab() const;
   const GURL GetManifestScope() const;
+  bool IsInstalledWebappDelegateGeolocation() const;
 
  private:
+  std::unique_ptr<device::mojom::GeolocationContext>
+      installed_webapp_geolocation_context_;
+
   ScopedObserver<find_in_page::FindTabHelper, find_in_page::FindResultObserver>
       find_result_observer_{this};
 
diff --git a/chrome/browser/android/vr/gl_browser_interface.h b/chrome/browser/android/vr/gl_browser_interface.h
index b126791..64e0898c 100644
--- a/chrome/browser/android/vr/gl_browser_interface.h
+++ b/chrome/browser/android/vr/gl_browser_interface.h
@@ -11,7 +11,6 @@
 #include "chrome/browser/vr/assets_load_status.h"
 #include "chrome/browser/vr/ui_test_input.h"
 #include "device/vr/public/mojom/vr_service.mojom.h"
-#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 #include "ui/gfx/transform.h"
 
 namespace gl {
@@ -30,7 +29,7 @@
                                      gl::SurfaceTexture* texture) = 0;
   virtual void ContentOverlaySurfaceCreated(jobject surface,
                                             gl::SurfaceTexture* texture) = 0;
-  virtual void GvrDelegateReady(gvr::ViewerType viewer_type) = 0;
+  virtual void GvrDelegateReady() = 0;
   // XRSessionPtr is optional, if null, the request failed.
   virtual void SendRequestPresentReply(device::mojom::XRSessionPtr) = 0;
   virtual void DialogSurfaceCreated(jobject surface,
diff --git a/chrome/browser/android/vr/gvr_graphics_delegate.cc b/chrome/browser/android/vr/gvr_graphics_delegate.cc
index bc6d30a6..c2b8d99 100644
--- a/chrome/browser/android/vr/gvr_graphics_delegate.cc
+++ b/chrome/browser/android/vr/gvr_graphics_delegate.cc
@@ -361,7 +361,7 @@
 
   UpdateViewports();
 
-  browser_->GvrDelegateReady(gvr_api_->GetViewerType());
+  browser_->GvrDelegateReady();
 }
 
 void GvrGraphicsDelegate::UpdateViewports() {
diff --git a/chrome/browser/android/vr/metrics_util_android.cc b/chrome/browser/android/vr/metrics_util_android.cc
index e07b22b5..d69fb66 100644
--- a/chrome/browser/android/vr/metrics_util_android.cc
+++ b/chrome/browser/android/vr/metrics_util_android.cc
@@ -5,74 +5,10 @@
 #include "chrome/browser/android/vr/metrics_util_android.h"
 
 #include "base/metrics/histogram_functions.h"
-#include "base/metrics/histogram_macros.h"
+#include "device/vr/vr_device.h"
 
-static constexpr int kVersionEncodingError = -4;
-static constexpr int kVrNotSupported = -3;
-static constexpr int kGvrNotInstalled = -2;
-static constexpr int kGvrTooOld = -1;
-
-namespace vr {
-
-bool MetricsUtilAndroid::has_logged_vr_runtime_version_ = false;
-
-void MetricsUtilAndroid::LogGvrVersionForVrViewerType(
-    gvr::ViewerType viewer_type,
-    const VrCoreInfo& vr_core_info) {
-  if (has_logged_vr_runtime_version_) {
-    return;
-  }
-
-  uint32_t encoded_version = kVersionEncodingError;
-  switch (vr_core_info.compatibility) {
-    case VrCoreCompatibility::VR_CORE_COMPATIBILITY_VR_NOT_SUPPORTED:
-      encoded_version = kVrNotSupported;
-      break;
-    case VrCoreCompatibility::VR_CORE_COMPATIBILITY_VR_NOT_AVAILABLE:
-      encoded_version = kGvrNotInstalled;
-      break;
-    case VrCoreCompatibility::VR_CORE_COMPATIBILITY_VR_OUT_OF_DATE:
-      if (vr_core_info.gvr_sdk_version.major == 0 &&
-          vr_core_info.gvr_sdk_version.minor == 0 &&
-          vr_core_info.gvr_sdk_version.patch == 0) {
-        encoded_version = kGvrTooOld;
-        break;
-      }
-      // Fall through since a version can be logged in this case.
-      FALLTHROUGH;
-    case VrCoreCompatibility::VR_CORE_COMPATIBILITY_VR_READY:
-      encoded_version =
-          std::min(vr_core_info.gvr_sdk_version.major, 999) * 1000 * 1000 +
-          std::min(vr_core_info.gvr_sdk_version.minor, 999) * 1000 +
-          std::min(vr_core_info.gvr_sdk_version.patch, 999);
-      break;
-  }
-
-  switch (GetVrViewerType(viewer_type)) {
-    case device::VrViewerType::GVR_CARDBOARD:
-      base::UmaHistogramSparse("VRRuntimeVersion.GVR.Cardboard",
-                               encoded_version);
-      break;
-    case device::VrViewerType::GVR_DAYDREAM:
-      base::UmaHistogramSparse("VRRuntimeVersion.GVR.Daydream",
-                               encoded_version);
-      break;
-    default:
-      NOTREACHED();
-      base::UmaHistogramSparse("VRRuntimeVersion.GVR.Unknown", encoded_version);
-      break;
-  }
-
-  has_logged_vr_runtime_version_ = true;
-}
-
-void MetricsUtilAndroid::LogVrViewerType(gvr::ViewerType viewer_type) {
-  base::UmaHistogramSparse("VRViewerType",
-                           static_cast<int>(GetVrViewerType(viewer_type)));
-}
-
-device::VrViewerType MetricsUtilAndroid::GetVrViewerType(
-    gvr::ViewerType viewer_type) {
+namespace {
+device::VrViewerType GetVrViewerType(gvr::ViewerType viewer_type) {
   switch (viewer_type) {
     case gvr::ViewerType::GVR_VIEWER_TYPE_DAYDREAM:
       return device::VrViewerType::GVR_DAYDREAM;
@@ -83,5 +19,11 @@
       return device::VrViewerType::GVR_UNKNOWN;
   }
 }
+}  // anonymous namespace
 
+namespace vr {
+void MetricsUtilAndroid::LogVrViewerType(gvr::ViewerType viewer_type) {
+  base::UmaHistogramSparse("VRViewerType",
+                           static_cast<int>(GetVrViewerType(viewer_type)));
+}
 }  // namespace vr
diff --git a/chrome/browser/android/vr/metrics_util_android.h b/chrome/browser/android/vr/metrics_util_android.h
index 50f213a..95e9b03 100644
--- a/chrome/browser/android/vr/metrics_util_android.h
+++ b/chrome/browser/android/vr/metrics_util_android.h
@@ -7,9 +7,6 @@
 
 #include "base/macros.h"
 
-#include "chrome/browser/android/vr/vr_core_info.h"
-#include "chrome/browser/vr/ui_suppressed_element.h"
-#include "device/vr/vr_device.h"
 #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 
 namespace vr {
@@ -17,8 +14,7 @@
 // A utility class containing static functions for metrics logging.
 class MetricsUtilAndroid {
  public:
-  // Ensure that this stays in sync with XRRenderPath in enums.xml. Do
-  // not reuse or renumber entries.
+  // TODO(klausw): Move this to gvr_scheduler_delegate.
   enum class XRRenderPath : int {
     kClientWait = 0,
     kGpuFence = 1,
@@ -28,16 +24,7 @@
     kCount
   };
 
-  static void LogGvrVersionForVrViewerType(gvr::ViewerType viewer_type,
-                                           const VrCoreInfo& vr_core_info);
   static void LogVrViewerType(gvr::ViewerType viewer_type);
-
- private:
-  static device::VrViewerType GetVrViewerType(gvr::ViewerType viewer_type);
-
-  static bool has_logged_vr_runtime_version_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(MetricsUtilAndroid);
 };
 
 }  // namespace vr
diff --git a/chrome/browser/android/vr/vr_gl_thread.cc b/chrome/browser/android/vr/vr_gl_thread.cc
index ab90297..35420e65 100644
--- a/chrome/browser/android/vr/vr_gl_thread.cc
+++ b/chrome/browser/android/vr/vr_gl_thread.cc
@@ -104,11 +104,10 @@
                                 surface, base::Unretained(texture)));
 }
 
-void VrGLThread::GvrDelegateReady(gvr::ViewerType viewer_type) {
+void VrGLThread::GvrDelegateReady() {
   DCHECK(OnGlThread());
   main_thread_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&VrShell::GvrDelegateReady, weak_vr_shell_, viewer_type));
+      FROM_HERE, base::BindOnce(&VrShell::GvrDelegateReady, weak_vr_shell_));
 }
 
 void VrGLThread::SendRequestPresentReply(device::mojom::XRSessionPtr session) {
diff --git a/chrome/browser/android/vr/vr_gl_thread.h b/chrome/browser/android/vr/vr_gl_thread.h
index 47310cd..b774a10 100644
--- a/chrome/browser/android/vr/vr_gl_thread.h
+++ b/chrome/browser/android/vr/vr_gl_thread.h
@@ -22,7 +22,6 @@
 #include "chrome/browser/vr/text_input_delegate.h"
 #include "chrome/browser/vr/ui_browser_interface.h"
 #include "chrome/browser/vr/ui_test_input.h"
-#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 
 namespace base {
 class Version;
@@ -67,7 +66,7 @@
                              gl::SurfaceTexture* texture) override;
   void ContentOverlaySurfaceCreated(jobject surface,
                                     gl::SurfaceTexture* texture) override;
-  void GvrDelegateReady(gvr::ViewerType viewer_type) override;
+  void GvrDelegateReady() override;
   void SendRequestPresentReply(device::mojom::XRSessionPtr) override;
   void DialogSurfaceCreated(jobject surface,
                             gl::SurfaceTexture* texture) override;
diff --git a/chrome/browser/android/vr/vr_shell.cc b/chrome/browser/android/vr/vr_shell.cc
index 4347e62..3cb5e3f 100644
--- a/chrome/browser/android/vr/vr_shell.cc
+++ b/chrome/browser/android/vr/vr_shell.cc
@@ -12,7 +12,6 @@
 
 #include "base/android/jni_string.h"
 #include "base/bind.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/platform_thread.h"
@@ -38,7 +37,6 @@
 #include "chrome/browser/vr/assets_loader.h"
 #include "chrome/browser/vr/browser_renderer.h"
 #include "chrome/browser/vr/location_bar_helper.h"
-#include "chrome/browser/vr/metrics/metrics_helper.h"
 #include "chrome/browser/vr/model/assets.h"
 #include "chrome/browser/vr/model/omnibox_suggestions.h"
 #include "chrome/browser/vr/model/text_input_info.h"
@@ -183,7 +181,6 @@
 
   AssetsLoader::GetInstance()->SetOnComponentReadyCallback(base::BindRepeating(
       &VrShell::OnAssetsComponentReady, weak_ptr_factory_.GetWeakPtr()));
-  AssetsLoader::GetInstance()->GetMetricsHelper()->OnEnter(Mode::kVr);
 
   UpdateVrAssetsComponent(g_browser_process->component_updater());
 
@@ -450,13 +447,6 @@
   // permissions.
   CreatePageInfo();
   ui_->SetWebVrMode(enabled);
-
-  if (webvr_mode_) {
-    AssetsLoader::GetInstance()->GetMetricsHelper()->OnEnter(
-        Mode::kWebXrVrPresentation);
-  } else {
-    AssetsLoader::GetInstance()->GetMetricsHelper()->OnEnter(Mode::kVrBrowsing);
-  }
 }
 
 bool VrShell::GetWebVrMode(JNIEnv* env, const JavaParamRef<jobject>& obj) {
@@ -641,8 +631,8 @@
   Java_VrShell_dialogSurfaceCreated(env, j_vr_shell_, ref);
 }
 
-void VrShell::GvrDelegateReady(gvr::ViewerType viewer_type) {
-  delegate_provider_->SetDelegate(this, viewer_type);
+void VrShell::GvrDelegateReady() {
+  delegate_provider_->SetDelegate(this);
 }
 
 void VrShell::SendRequestPresentReply(device::mojom::XRSessionPtr session) {
@@ -704,12 +694,6 @@
   }
 }
 
-void VrShell::LogUnsupportedModeUserMetric(JNIEnv* env,
-                                           const JavaParamRef<jobject>& obj,
-                                           int mode) {
-  LogUnsupportedModeUserMetric((UiUnsupportedMode)mode);
-}
-
 void VrShell::ShowSoftInput(JNIEnv* env,
                             const base::android::JavaParamRef<jobject>& obj,
                             bool show) {
@@ -729,11 +713,6 @@
                                            composition_start, composition_end));
 }
 
-void VrShell::LogUnsupportedModeUserMetric(UiUnsupportedMode mode) {
-  UMA_HISTOGRAM_ENUMERATION("VR.Shell.EncounteredUnsupportedMode", mode,
-                            UiUnsupportedMode::kCount);
-}
-
 content::WebContents* VrShell::GetNonNativePageWebContents() const {
   return !web_contents_is_native_page_ ? web_contents_ : nullptr;
 }
@@ -785,19 +764,9 @@
   }
 
   DCHECK_NE(reason, UiUnsupportedMode::kCount);
-  if (reason == UiUnsupportedMode::kVoiceSearchNeedsRecordAudioOsPermission) {
-    // Note that we already measure the number of times the user exits VR
-    // because of the record audio permission through
-    // VR.Shell.EncounteredUnsupportedMode histogram. This histogram measures
-    // whether the user chose to proceed to grant the OS record audio permission
-    // through the reported Boolean.
-    UMA_HISTOGRAM_BOOLEAN("VR.VoiceSearch.RecordAudioOsPermissionPromptChoice",
-                          choice == ExitVrPromptChoice::CHOICE_EXIT);
-  }
 
   JNIEnv* env = base::android::AttachCurrentThread();
-  Java_VrShell_onExitVrRequestResult(env, j_vr_shell_, static_cast<int>(reason),
-                                     should_exit);
+  Java_VrShell_onExitVrRequestResult(env, j_vr_shell_, should_exit);
 }
 
 void VrShell::OnContentScreenBoundsChanged(const gfx::SizeF& bounds) {
@@ -1045,8 +1014,6 @@
     VLOG(1) << "Failed to load VR assets component";
   }
 
-  AssetsLoader::GetInstance()->GetMetricsHelper()->OnAssetsLoaded(
-      status, component_version);
   ui_finished_loading_ = true;
 }
 
diff --git a/chrome/browser/android/vr/vr_shell.h b/chrome/browser/android/vr/vr_shell.h
index ad734a7..f9e1754f 100644
--- a/chrome/browser/android/vr/vr_shell.h
+++ b/chrome/browser/android/vr/vr_shell.h
@@ -150,10 +150,6 @@
   void RequestToExitVr(JNIEnv* env,
                        const base::android::JavaParamRef<jobject>& obj,
                        int reason);
-  void LogUnsupportedModeUserMetric(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj,
-      int mode);
 
   void ShowSoftInput(JNIEnv* env,
                      const base::android::JavaParamRef<jobject>& obj,
@@ -176,7 +172,7 @@
   void ContentSurfaceCreated(jobject surface, gl::SurfaceTexture* texture);
   void ContentOverlaySurfaceCreated(jobject surface,
                                     gl::SurfaceTexture* texture);
-  void GvrDelegateReady(gvr::ViewerType viewer_type);
+  void GvrDelegateReady();
   void SendRequestPresentReply(device::mojom::XRSessionPtr);
 
   void DialogSurfaceCreated(jobject surface, gl::SurfaceTexture* texture);
@@ -191,7 +187,6 @@
   void ForceExitVr();
   void ExitPresent();
   void ExitFullscreen();
-  void LogUnsupportedModeUserMetric(UiUnsupportedMode mode);
   void OnUnsupportedMode(UiUnsupportedMode mode);
   void OnExitVrPromptResult(UiUnsupportedMode reason,
                             ExitVrPromptChoice choice);
diff --git a/chrome/browser/android/vr/vr_shell_delegate.cc b/chrome/browser/android/vr/vr_shell_delegate.cc
index 596af611..47ae1204 100644
--- a/chrome/browser/android/vr/vr_shell_delegate.cc
+++ b/chrome/browser/android/vr/vr_shell_delegate.cc
@@ -10,12 +10,10 @@
 #include "base/bind.h"
 #include "chrome/android/features/vr/jni_headers/VrShellDelegate_jni.h"
 #include "chrome/browser/android/vr/arcore_device/arcore_device_provider.h"
-#include "chrome/browser/android/vr/metrics_util_android.h"
 #include "chrome/browser/android/vr/vr_shell.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/component_updater/vr_assets_component_installer.h"
 #include "chrome/browser/vr/assets_loader.h"
-#include "chrome/browser/vr/metrics/metrics_helper.h"
 #include "content/public/browser/browser_xr_runtime.h"
 #include "content/public/browser/xr_runtime_manager.h"
 #include "device/vr/android/gvr/gvr_delegate_provider_factory.h"
@@ -92,8 +90,7 @@
       Java_VrShellDelegate_getNativePointer(env, jdelegate));
 }
 
-void VrShellDelegate::SetDelegate(VrShell* vr_shell,
-                                  gvr::ViewerType viewer_type) {
+void VrShellDelegate::SetDelegate(VrShell* vr_shell) {
   vr_shell_ = vr_shell;
 
   // When VrShell is created, we disable magic window mode as the user is inside
@@ -112,10 +109,6 @@
     pending_successful_present_request_ = false;
     std::move(on_present_result_callback_).Run(true);
   }
-
-  JNIEnv* env = AttachCurrentThread();
-  std::unique_ptr<VrCoreInfo> vr_core_info = MakeVrCoreInfo(env);
-  MetricsUtilAndroid::LogGvrVersionForVrViewerType(viewer_type, *vr_core_info);
 }
 
 void VrShellDelegate::RemoveDelegate() {
diff --git a/chrome/browser/android/vr/vr_shell_delegate.h b/chrome/browser/android/vr/vr_shell_delegate.h
index 931487c0..dbb03fc 100644
--- a/chrome/browser/android/vr/vr_shell_delegate.h
+++ b/chrome/browser/android/vr/vr_shell_delegate.h
@@ -49,7 +49,7 @@
       JNIEnv* env,
       const base::android::JavaRef<jobject>& jdelegate);
 
-  void SetDelegate(VrShell* vr_shell, gvr::ViewerType viewer_type);
+  void SetDelegate(VrShell* vr_shell);
   void RemoveDelegate();
 
   void SetPresentResult(JNIEnv* env,
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 1e1acf4..baab781 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -4132,7 +4132,7 @@
   auto* find_helper =
       find_in_page::FindTabHelper::FromWebContents(embedder_web_contents);
   find_helper->StartFinding(base::ASCIIToUTF16("doesn't matter"), true, true,
-                            false);
+                            true);
   auto pending =
       content::GetRenderFrameHostsWithPendingFindResults(embedder_web_contents);
   // Request for main frame of the tab.
diff --git a/chrome/browser/browsing_data/browsing_data_quota_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_quota_helper_unittest.cc
index d2bd42d..a860cdc 100644
--- a/chrome/browser/browsing_data/browsing_data_quota_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_quota_helper_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/bind.h"
 #include "base/containers/span.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/stl_util.h"
 #include "chrome/browser/browsing_data/browsing_data_quota_helper_impl.h"
@@ -15,6 +16,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_utils.h"
+#include "storage/browser/quota/quota_client_type.h"
 #include "storage/browser/quota/quota_manager.h"
 #include "storage/browser/quota/quota_manager_proxy.h"
 #include "storage/browser/test/mock_quota_client.h"
@@ -68,7 +70,8 @@
     MockQuotaClient* client =
         new MockQuotaClient(quota_manager_->proxy(), origin_data,
                             storage::QuotaClientType::kFileSystem);
-    quota_manager_->proxy()->RegisterClient(client);
+    quota_manager_->proxy()->RegisterClient(
+        client, storage::QuotaClientType::kFileSystem);
     client->TouchAllOriginsAndNotify();
   }
 
diff --git a/chrome/browser/chrome_find_request_manager_browsertest.cc b/chrome/browser/chrome_find_request_manager_browsertest.cc
index 028053d2..e0d7154 100644
--- a/chrome/browser/chrome_find_request_manager_browsertest.cc
+++ b/chrome/browser/chrome_find_request_manager_browsertest.cc
@@ -106,7 +106,7 @@
   delegate()->MarkNextReply();
   delegate()->WaitForNextReply();
 
-  options->find_next = true;
+  options->new_session = false;
   Find("result", options.Clone());
   delegate()->MarkNextReply();
   delegate()->WaitForNextReply();
@@ -234,7 +234,7 @@
   // Verify that find-in-page works fine.
   auto options = blink::mojom::FindOptions::New();
   Find("FXCMAP_CMap", options.Clone());
-  options->find_next = true;
+  options->new_session = false;
   Find("FXCMAP_CMap", options.Clone());
   Find("FXCMAP_CMap", options.Clone());
   delegate()->WaitForFinalReply();
@@ -259,7 +259,7 @@
   ASSERT_TRUE(pdf_extension_test_util::EnsurePDFHasLoaded(contents()));
 
   auto options = blink::mojom::FindOptions::New();
-  options->find_next = true;
+  options->new_session = false;
   Find("result", options.Clone());
   options->forward = false;
   Find("result", options.Clone());
diff --git a/chrome/browser/chrome_resource_bundle_helper.cc b/chrome/browser/chrome_resource_bundle_helper.cc
index 4672bb8..507cbbb0 100644
--- a/chrome/browser/chrome_resource_bundle_helper.cc
+++ b/chrome/browser/chrome_resource_bundle_helper.cc
@@ -66,8 +66,11 @@
   // not have been created yet.
   DCHECK(!ui::ResourceBundle::HasSharedInstance());
   // Auto-detect based on en-US whether secondary locale .pak files exist.
+  bool in_split = false;
+  bool log_error = false;
   ui::SetLoadSecondaryLocalePaks(
-      !ui::GetPathForAndroidLocalePakWithinApk("en-US").empty());
+      !ui::GetPathForAndroidLocalePakWithinApk("en-US", in_split, log_error)
+           .empty());
 #endif
 
   std::string preferred_locale;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 73a4bff2..84c0275 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -3046,8 +3046,6 @@
     "local_search_service/index_unittest.cc",
     "local_search_service/inverted_index_unittest.cc",
     "local_search_service/local_search_service_unittest.cc",
-    "local_search_service/test_utils.cc",
-    "local_search_service/test_utils.h",
     "locale_change_guard_unittest.cc",
     "lock_screen_apps/app_manager_impl_unittest.cc",
     "lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc",
diff --git a/chrome/browser/chromeos/DEPS b/chrome/browser/chromeos/DEPS
index 94802876..fe6631a 100644
--- a/chrome/browser/chromeos/DEPS
+++ b/chrome/browser/chromeos/DEPS
@@ -31,7 +31,6 @@
   ".*test.*": [
    "!ash",
    "+ash/public",
-   "+ash/keyboard/ui/public",
   ],
   "assistant_util_unittest\.cc": [
     "+ui/events/devices/device_data_manager.h",
diff --git a/chrome/browser/chromeos/app_mode/app_launch_utils.cc b/chrome/browser/chromeos/app_mode/app_launch_utils.cc
index b066942e..1c46d7f6 100644
--- a/chrome/browser/chromeos/app_mode/app_launch_utils.cc
+++ b/chrome/browser/chromeos/app_mode/app_launch_utils.cc
@@ -64,7 +64,8 @@
   }
   void OnInstallingApp() override {}
   void OnReadyToLaunch() override { startup_app_launcher_->LaunchApp(); }
-  void OnLaunchSucceeded() override { Cleanup(); }
+  void OnLaunchSucceeded() override {}
+  void OnAppWindowCreated() override { Cleanup(); }
   void OnLaunchFailed(KioskAppLaunchError::Error error) override {
     KioskAppLaunchError::Save(error);
     chrome::AttemptUserExit();
diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
index 7e42483..ebae10d1 100644
--- a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
+++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
@@ -27,6 +27,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "components/crx_file/id_util.h"
 #include "components/session_manager/core/session_manager.h"
+#include "extensions/browser/app_window/app_window.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
@@ -59,7 +60,10 @@
   kiosk_app_manager_observer_.Add(KioskAppManager::Get());
 }
 
-StartupAppLauncher::~StartupAppLauncher() = default;
+StartupAppLauncher::~StartupAppLauncher() {
+  if (waiting_for_window_)
+    window_registry_->RemoveObserver(this);
+}
 
 void StartupAppLauncher::Initialize() {
   MaybeInitializeNetwork();
@@ -436,6 +440,24 @@
 
 void StartupAppLauncher::OnLaunchSuccess() {
   delegate_->OnLaunchSucceeded();
+
+  window_registry_ = extensions::AppWindowRegistry::Get(profile_);
+  // Start waiting for app window.
+  if (!window_registry_->GetAppWindowsForApp(app_id_).empty()) {
+    delegate_->OnAppWindowCreated();
+    return;
+  } else {
+    waiting_for_window_ = true;
+    window_registry_->AddObserver(this);
+  }
+}
+
+void StartupAppLauncher::OnAppWindowAdded(extensions::AppWindow* app_window) {
+  if (app_window->extension_id() == app_id_) {
+    waiting_for_window_ = false;
+    window_registry_->RemoveObserver(this);
+    delegate_->OnAppWindowCreated();
+  }
 }
 
 void StartupAppLauncher::OnLaunchFailure(KioskAppLaunchError::Error error) {
diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.h b/chrome/browser/chromeos/app_mode/startup_app_launcher.h
index 95d0826..b0a905b 100644
--- a/chrome/browser/chromeos/app_mode/startup_app_launcher.h
+++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.h
@@ -17,9 +17,14 @@
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h"
 #include "chrome/browser/extensions/install_observer.h"
 #include "chrome/browser/extensions/install_tracker.h"
+#include "extensions/browser/app_window/app_window_registry.h"
 
 class Profile;
 
+namespace extensions {
+class AppWindowRegistry;
+}
+
 namespace chromeos {
 
 class StartupAppLauncherUpdateChecker;
@@ -32,7 +37,8 @@
 // Report OnLauncherInitialized() or OnLaunchFailed() to observers:
 // - If all goes good, launches the app and finish the flow;
 class StartupAppLauncher : public extensions::InstallObserver,
-                           public KioskAppManagerObserver {
+                           public KioskAppManagerObserver,
+                           public extensions::AppWindowRegistry::Observer {
  public:
   class Delegate {
    public:
@@ -51,6 +57,7 @@
     virtual void OnReadyToLaunch() = 0;
     virtual void OnLaunchSucceeded() = 0;
     virtual void OnLaunchFailed(KioskAppLaunchError::Error error) = 0;
+    virtual void OnAppWindowCreated() {}
     virtual bool IsShowingNetworkConfigScreen() = 0;
 
    protected:
@@ -76,6 +83,9 @@
   void RestartLauncher();
 
  private:
+  // Class used to watch for app window creation.
+  class AppWindowWatcher;
+
   void OnLaunchSuccess();
   void OnLaunchFailure(KioskAppLaunchError::Error error);
 
@@ -93,6 +103,9 @@
 
   void OnKioskAppDataLoadStatusChanged(const std::string& app_id);
 
+  // AppWindowRegistry::Observer:
+  void OnAppWindowAdded(extensions::AppWindow* app_window) override;
+
   // Returns true if any secondary app is pending.
   bool IsAnySecondaryAppPending() const;
 
@@ -128,11 +141,14 @@
   bool ready_to_launch_ = false;
   bool wait_for_crx_update_ = false;
   bool secondary_apps_installed_ = false;
+  bool waiting_for_window_ = false;
 
   // Used to run extension update checks for primary app's imports and
   // secondary extensions.
   std::unique_ptr<StartupAppLauncherUpdateChecker> update_checker_;
 
+  extensions::AppWindowRegistry* window_registry_;
+
   ScopedObserver<KioskAppManagerBase, KioskAppManagerObserver>
       kiosk_app_manager_observer_{this};
 
diff --git a/chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.cc b/chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.cc
index 51fb9ad..6b2be6c 100644
--- a/chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.cc
+++ b/chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.cc
@@ -391,8 +391,18 @@
 
   std::string state_description;
   if (GetProperty(AXStringProperty::STATE_DESCRIPTION, &state_description)) {
-    out_data->AddStringAttribute(ax::mojom::StringAttribute::kDescription,
-                                 state_description);
+    // kValue (aria-valuetext) is supported on widgets with range_info. In this
+    // case, using kValue over kDescription is closer to the usage of
+    // stateDescription.
+    if (node_ptr_->range_info) {
+      out_data->AddStringAttribute(ax::mojom::StringAttribute::kValue,
+                                   state_description);
+    } else {
+      // TODO(sahok): Append strings anotated as kDescription(which is now
+      // overwritten)
+      out_data->AddStringAttribute(ax::mojom::StringAttribute::kDescription,
+                                   state_description);
+    }
   }
 
   // Int properties.
diff --git a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc_unittest.cc b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc_unittest.cc
index 0643c19..753136695 100644
--- a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc_unittest.cc
+++ b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc_unittest.cc
@@ -1571,4 +1571,56 @@
   EXPECT_EQ(1, GetDispatchedEventCount(ax::mojom::Event::kLiveRegionChanged));
 }
 
+TEST_F(AXTreeSourceArcTest, StateDescriptionWithRange) {
+  auto event = AXEventData::New();
+  event->source_id = 0;
+  event->task_id = 1;
+  event->event_type = AXEventType::VIEW_FOCUSED;
+
+  event->window_data = std::vector<mojom::AccessibilityWindowInfoDataPtr>();
+  event->window_data->push_back(AXWindowInfoData::New());
+  AXWindowInfoData* root_window = event->window_data->back().get();
+  root_window->window_id = 100;
+  root_window->root_node_id = 10;
+
+  event->node_data.push_back(AXNodeInfoData::New());
+  AXNodeInfoData* root = event->node_data.back().get();
+  root->id = 10;
+
+  // Populate the tree source with the data.
+  CallNotifyAccessibilityEvent(event.get());
+
+  // No attributes.
+  ui::AXNodeData data;
+  data = GetSerializedNode(root->id);
+  std::string description;
+  ASSERT_FALSE(data.GetStringAttribute(ax::mojom::StringAttribute::kDescription,
+                                       &description));
+  std::string value;
+  ASSERT_FALSE(
+      data.GetStringAttribute(ax::mojom::StringAttribute::kValue, &value));
+
+  // State Description without Range Value should be stored as kDescription
+  SetProperty(root, AXStringProperty::STATE_DESCRIPTION, "state description");
+
+  CallNotifyAccessibilityEvent(event.get());
+  data = GetSerializedNode(root->id);
+  ASSERT_TRUE(data.GetStringAttribute(ax::mojom::StringAttribute::kDescription,
+                                      &description));
+  EXPECT_EQ("state description", description);
+  ASSERT_FALSE(
+      data.GetStringAttribute(ax::mojom::StringAttribute::kValue, &value));
+
+  // State Description with Range Value should be stored as kValue
+  root->range_info = AXRangeInfoData::New();
+
+  CallNotifyAccessibilityEvent(event.get());
+  data = GetSerializedNode(root->id);
+  ASSERT_FALSE(data.GetStringAttribute(ax::mojom::StringAttribute::kDescription,
+                                       &description));
+  ASSERT_TRUE(
+      data.GetStringAttribute(ax::mojom::StringAttribute::kValue, &value));
+  EXPECT_EQ("state description", value);
+}
+
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.cc b/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.cc
index e3bb389..597fa2a7 100644
--- a/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.cc
+++ b/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.cc
@@ -602,6 +602,9 @@
 void ArcBluetoothBridge::DeviceMTUChanged(BluetoothAdapter* adapter,
                                           BluetoothDevice* device,
                                           uint16_t mtu) {
+  if (!arc_bridge_service_->bluetooth()->IsConnected())
+    return;
+
   auto* bluetooth_instance = ARC_GET_INSTANCE_FOR_METHOD(
       arc_bridge_service_->bluetooth(), OnMTUReceived);
   if (!device->IsConnected() || bluetooth_instance == nullptr)
@@ -615,6 +618,9 @@
     BluetoothDevice* device,
     int16_t rssi,
     const std::vector<uint8_t>& eir) {
+  if (!arc_bridge_service_->bluetooth()->IsConnected())
+    return;
+
   constexpr int kAndroidPSdkVersion = 28;
   base::Optional<int> sdk_version = SdkVersion();
   mojom::BluetoothAddressPtr addr =
diff --git a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc
index cdd2fd9..352c6071 100644
--- a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc
+++ b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc
@@ -132,13 +132,13 @@
 };
 
 class ArcInputMethodManagerService::InputMethodEngineObserver
-    : public input_method::InputMethodEngineBase::Observer {
+    : public chromeos::InputMethodEngineBase::Observer {
  public:
   explicit InputMethodEngineObserver(ArcInputMethodManagerService* owner)
       : owner_(owner) {}
   ~InputMethodEngineObserver() override = default;
 
-  // input_method::InputMethodEngineBase::Observer overrides:
+  // chromeos::InputMethodEngineBase::Observer overrides:
   void OnActivate(const std::string& engine_id) override {
     owner_->is_arc_ime_active_ = true;
     // TODO(yhanada): Remove this line after we migrate to SPM completely.
@@ -151,7 +151,7 @@
   void OnBlur(int context_id) override { owner_->Blur(); }
   void OnKeyEvent(
       const std::string& engine_id,
-      const input_method::InputMethodEngineBase::KeyboardEvent& event,
+      const chromeos::InputMethodEngineBase::KeyboardEvent& event,
       ui::IMEEngineHandlerInterface::KeyEventDoneCallback key_data) override {
     if (event.key_code == ui::VKEY_BROWSER_BACK &&
         owner_->IsVirtualKeyboardShown()) {
@@ -184,7 +184,7 @@
   void OnCandidateClicked(
       const std::string& component_id,
       int candidate_id,
-      input_method::InputMethodEngineBase::MouseButtonEvent button) override {}
+      chromeos::InputMethodEngineBase::MouseButtonEvent button) override {}
   void OnMenuItemActivated(const std::string& component_id,
                            const std::string& menu_id) override {}
   void OnScreenProjectionChanged(bool is_projected) override {}
diff --git a/chrome/browser/chromeos/arc/input_method_manager/input_connection_impl.cc b/chrome/browser/chromeos/arc/input_method_manager/input_connection_impl.cc
index 993ec6a4..7694d77 100644
--- a/chrome/browser/chromeos/arc/input_method_manager/input_connection_impl.cc
+++ b/chrome/browser/chromeos/arc/input_method_manager/input_connection_impl.cc
@@ -223,7 +223,7 @@
   if (!ime_engine_->SetComposition(
           input_context_id_, base::UTF16ToUTF8(text).c_str(), selection_start,
           selection_end, new_cursor_pos,
-          std::vector<input_method::InputMethodEngineBase::SegmentInfo>(),
+          std::vector<chromeos::InputMethodEngineBase::SegmentInfo>(),
           &error)) {
     LOG(ERROR) << "SetComposingText failed: pos=" << new_cursor_pos
                << ", error=\"" << error << "\"";
@@ -293,14 +293,13 @@
 
   const int before = selection_range.start() - new_composition_range.start();
   const int after = new_composition_range.end() - selection_range.end();
-  input_method::InputMethodEngineBase::SegmentInfo segment_info;
+  chromeos::InputMethodEngineBase::SegmentInfo segment_info;
   segment_info.start = 0;
   segment_info.end = new_composition_range.length();
-  segment_info.style =
-      input_method::InputMethodEngineBase::SEGMENT_STYLE_UNDERLINE;
+  segment_info.style = chromeos::InputMethodEngineBase::SEGMENT_STYLE_UNDERLINE;
 
   std::string error;
-  if (!ime_engine_->input_method::InputMethodEngineBase::SetCompositionRange(
+  if (!ime_engine_->chromeos::InputMethodEngineBase::SetCompositionRange(
           input_context_id_, before, after, {segment_info}, &error)) {
     LOG(ERROR) << "SetCompositionRange failed: range="
                << new_composition_range.ToString() << ", error=\"" << error
diff --git a/chrome/browser/chromeos/arc/input_method_manager/input_connection_impl_unittest.cc b/chrome/browser/chromeos/arc/input_method_manager/input_connection_impl_unittest.cc
index c2f26e44..80445fb 100644
--- a/chrome/browser/chromeos/arc/input_method_manager/input_connection_impl_unittest.cc
+++ b/chrome/browser/chromeos/arc/input_method_manager/input_connection_impl_unittest.cc
@@ -21,7 +21,7 @@
 namespace {
 
 class DummyInputMethodEngineObserver
-    : public input_method::InputMethodEngineBase::Observer {
+    : public chromeos::InputMethodEngineBase::Observer {
  public:
   DummyInputMethodEngineObserver() = default;
   ~DummyInputMethodEngineObserver() override = default;
@@ -32,7 +32,7 @@
   void OnBlur(int context_id) override {}
   void OnKeyEvent(
       const std::string& engine_id,
-      const input_method::InputMethodEngineBase::KeyboardEvent& event,
+      const chromeos::InputMethodEngineBase::KeyboardEvent& event,
       ui::IMEEngineHandlerInterface::KeyEventDoneCallback key_data) override {}
   void OnReset(const std::string& engine_id) override {}
   void OnDeactivated(const std::string& engine_id) override {}
@@ -48,7 +48,7 @@
   void OnCandidateClicked(
       const std::string& component_id,
       int candidate_id,
-      input_method::InputMethodEngineBase::MouseButtonEvent button) override {}
+      chromeos::InputMethodEngineBase::MouseButtonEvent button) override {}
   void OnMenuItemActivated(const std::string& component_id,
                            const std::string& menu_id) override {}
   void OnScreenProjectionChanged(bool is_projected) override {}
diff --git a/chrome/browser/chromeos/extensions/input_method_api.cc b/chrome/browser/chromeos/extensions/input_method_api.cc
index 5576c3b..5e337a9 100644
--- a/chrome/browser/chromeos/extensions/input_method_api.cc
+++ b/chrome/browser/chromeos/extensions/input_method_api.cc
@@ -73,7 +73,7 @@
 namespace OnSettingsChanged =
     extensions::api::input_method_private::OnSettingsChanged;
 
-using input_method::InputMethodEngineBase;
+using chromeos::InputMethodEngineBase;
 
 namespace {
 
diff --git a/chrome/browser/chromeos/fileapi/recent_arc_media_source.cc b/chrome/browser/chromeos/fileapi/recent_arc_media_source.cc
index 3826d59b..775622a 100644
--- a/chrome/browser/chromeos/fileapi/recent_arc_media_source.cc
+++ b/chrome/browser/chromeos/fileapi/recent_arc_media_source.cc
@@ -34,6 +34,7 @@
 namespace {
 
 const char kAndroidDownloadDirPrefix[] = "/storage/emulated/0/Download/";
+const char kAndroidMyFilesDirPrefix[] = "/storage/MyFiles/";
 
 const char kMediaDocumentsProviderAuthority[] =
     "com.android.providers.media.documents";
@@ -56,6 +57,18 @@
   return relative_mount_path;
 }
 
+bool IsInsideDownloadsOrMyFiles(const std::string& path) {
+  if (base::StartsWith(path, kAndroidDownloadDirPrefix,
+                       base::CompareCase::SENSITIVE)) {
+    return true;
+  }
+  if (base::StartsWith(path, kAndroidMyFilesDirPrefix,
+                       base::CompareCase::SENSITIVE)) {
+    return true;
+  }
+  return false;
+}
+
 }  // namespace
 
 const char RecentArcMediaSource::kLoadHistogramName[] =
@@ -170,14 +183,13 @@
   // Initialize |document_id_to_file_| with recent document IDs returned.
   if (maybe_documents.has_value()) {
     for (const auto& document : maybe_documents.value()) {
-      // Exclude media files under Downloads directory since they are covered
-      // by RecentDownloadSource.
+      // Exclude media files under Downloads or MyFiles directory since they are
+      // covered by RecentDiskSource.
       if (document->android_file_system_path.has_value() &&
-          base::StartsWith(document->android_file_system_path.value(),
-                           kAndroidDownloadDirPrefix,
-                           base::CompareCase::SENSITIVE))
+          IsInsideDownloadsOrMyFiles(
+              document->android_file_system_path.value())) {
         continue;
-
+      }
       document_id_to_file_.emplace(document->document_id, base::nullopt);
     }
   }
diff --git a/chrome/browser/chromeos/input_method/assistive_suggester.cc b/chrome/browser/chromeos/input_method/assistive_suggester.cc
index e94aad12..247c3347 100644
--- a/chrome/browser/chromeos/input_method/assistive_suggester.cc
+++ b/chrome/browser/chromeos/input_method/assistive_suggester.cc
@@ -13,8 +13,6 @@
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 
-using input_method::InputMethodEngineBase;
-
 namespace chromeos {
 
 namespace {
diff --git a/chrome/browser/chromeos/input_method/assistive_suggester.h b/chrome/browser/chromeos/input_method/assistive_suggester.h
index 763e4d5..cced889 100644
--- a/chrome/browser/chromeos/input_method/assistive_suggester.h
+++ b/chrome/browser/chromeos/input_method/assistive_suggester.h
@@ -48,8 +48,7 @@
 
   // Called when the user pressed a key.
   // Returns true if suggester handles the event and it should stop propagate.
-  bool OnKeyEvent(
-      const ::input_method::InputMethodEngineBase::KeyboardEvent& event);
+  bool OnKeyEvent(const InputMethodEngineBase::KeyboardEvent& event);
 
  private:
   // Returns if any suggestion text should be displayed according to the
diff --git a/chrome/browser/chromeos/input_method/emoji_suggester.cc b/chrome/browser/chromeos/input_method/emoji_suggester.cc
index a732f56..0e97967 100644
--- a/chrome/browser/chromeos/input_method/emoji_suggester.cc
+++ b/chrome/browser/chromeos/input_method/emoji_suggester.cc
@@ -14,8 +14,6 @@
 #include "base/task/thread_pool.h"
 #include "chromeos/services/ime/constants.h"
 
-using input_method::InputMethodEngineBase;
-
 namespace chromeos {
 
 namespace {
diff --git a/chrome/browser/chromeos/input_method/emoji_suggester.h b/chrome/browser/chromeos/input_method/emoji_suggester.h
index ca842bcf..931f198d 100644
--- a/chrome/browser/chromeos/input_method/emoji_suggester.h
+++ b/chrome/browser/chromeos/input_method/emoji_suggester.h
@@ -25,8 +25,7 @@
   void OnFocus(int context_id) override;
   void OnBlur() override;
   SuggestionStatus HandleKeyEvent(
-      const ::input_method::InputMethodEngineBase::KeyboardEvent& event)
-      override;
+      const InputMethodEngineBase::KeyboardEvent& event) override;
   bool Suggest(const base::string16& text) override;
   void DismissSuggestion() override;
   AssistiveType GetProposeActionType() override;
diff --git a/chrome/browser/chromeos/input_method/input_method_engine.cc b/chrome/browser/chromeos/input_method/input_method_engine.cc
index 3135f0a6..036377a 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine.cc
@@ -37,8 +37,6 @@
 #include "ui/events/keycodes/dom/dom_code.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
 
-using input_method::InputMethodEngineBase;
-
 namespace chromeos {
 
 namespace {
diff --git a/chrome/browser/chromeos/input_method/input_method_engine.h b/chrome/browser/chromeos/input_method/input_method_engine.h
index cc745d9..91c26a15 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine.h
+++ b/chrome/browser/chromeos/input_method/input_method_engine.h
@@ -32,14 +32,11 @@
 }  // namespace ime
 }  // namespace ui
 
-namespace input_method {
-class InputMethodEngineBase;
-}  // namespace input_method
-
 namespace chromeos {
+
 struct AssistiveWindowProperties;
 
-class InputMethodEngine : public ::input_method::InputMethodEngineBase,
+class InputMethodEngine : public InputMethodEngineBase,
                           public SuggestionHandlerInterface {
  public:
   enum {
@@ -170,7 +167,7 @@
   bool IsValidKeyEvent(const ui::KeyEvent* ui_event) override;
 
  private:
-  // input_method::InputMethodEngineBase:
+  // InputMethodEngineBase:
   void UpdateComposition(const ui::CompositionText& composition_text,
                          uint32_t cursor_pos,
                          bool is_visible) override;
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_base.cc b/chrome/browser/chromeos/input_method/input_method_engine_base.cc
index fd08ec9..aefdeb3 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_base.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine_base.cc
@@ -28,7 +28,7 @@
 #include "ui/events/keycodes/dom/dom_code.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
 
-namespace input_method {
+namespace chromeos {
 
 namespace {
 
@@ -587,4 +587,4 @@
     input_context->ConfirmCompositionText(reset_engine, keep_selection);
 }
 
-}  // namespace input_method
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_base.h b/chrome/browser/chromeos/input_method/input_method_engine_base.h
index 2c2e1ea..ffd4b26 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_base.h
+++ b/chrome/browser/chromeos/input_method/input_method_engine_base.h
@@ -29,7 +29,7 @@
 }  // namespace ime
 }  // namespace ui
 
-namespace input_method {
+namespace chromeos {
 
 class InputMethodEngineBase : virtual public ui::IMEEngineHandlerInterface {
  public:
@@ -62,13 +62,11 @@
     SegmentStyle style;
   };
 
-#if defined(OS_CHROMEOS)
   enum MouseButtonEvent {
     MOUSE_BUTTON_LEFT,
     MOUSE_BUTTON_RIGHT,
     MOUSE_BUTTON_MIDDLE,
   };
-#endif
 
   class Observer {
    public:
@@ -107,8 +105,6 @@
                                           int anchor_pos,
                                           int offset_pos) = 0;
 
-#if defined(OS_CHROMEOS)
-
     // Called when an InputContext's properties change while it is focused.
     virtual void OnInputContextUpdate(
         const IMEEngineHandlerInterface::InputContext& context) = 0;
@@ -129,7 +125,6 @@
                                      const std::string& menu_id) = 0;
 
     virtual void OnScreenProjectionChanged(bool is_projected) = 0;
-#endif  // defined(OS_CHROMEOS)
   };
 
   InputMethodEngineBase();
@@ -323,6 +318,6 @@
   ui::KeyEvent ConvertKeyboardEventToUIKeyEvent(const KeyboardEvent& event);
 };
 
-}  // namespace input_method
+}  // namespace chromeos
 
 #endif  // CHROME_BROWSER_CHROMEOS_INPUT_METHOD_INPUT_METHOD_ENGINE_BASE_H_
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_unittest.cc b/chrome/browser/chromeos/input_method/input_method_engine_unittest.cc
index 180ee95..cbb51e0 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine_unittest.cc
@@ -32,8 +32,6 @@
 #include "ui/events/types/event_type.h"
 #include "ui/gfx/geometry/rect.h"
 
-using input_method::InputMethodEngineBase;
-
 namespace chromeos {
 
 namespace input_method {
@@ -341,7 +339,7 @@
   CreateEngine(true);
   const int context = engine_->GetContextIdForTesting();
   std::string error;
-  engine_->::input_method::InputMethodEngineBase::SetSelectionRange(
+  engine_->chromeos::InputMethodEngineBase::SetSelectionRange(
       context, /* start */ 0, /* end */ 0, &error);
   EXPECT_EQ(kErrorNotActive, error);
   EXPECT_EQ(0,
@@ -349,21 +347,21 @@
   error = "";
 
   engine_->Enable(kTestImeComponentId);
-  engine_->::input_method::InputMethodEngineBase::SetSelectionRange(
+  engine_->chromeos::InputMethodEngineBase::SetSelectionRange(
       context, /* start */ 0, /* end */ 0, &error);
   EXPECT_EQ("", error);
   EXPECT_EQ(1,
             mock_ime_input_context_handler_->set_selection_range_call_count());
   error = "";
 
-  engine_->::input_method::InputMethodEngineBase::SetSelectionRange(
+  engine_->chromeos::InputMethodEngineBase::SetSelectionRange(
       context, /* start */ -1, /* end */ 0, &error);
   EXPECT_EQ(base::StringPrintf(kErrorInvalidValue, "start", -1), error);
   EXPECT_EQ(1,
             mock_ime_input_context_handler_->set_selection_range_call_count());
   error = "";
 
-  engine_->::input_method::InputMethodEngineBase::SetSelectionRange(
+  engine_->chromeos::InputMethodEngineBase::SetSelectionRange(
       context, /* start */ 0, /* end */ -1, &error);
   EXPECT_EQ(base::StringPrintf(kErrorInvalidValue, "end", -1), error);
   EXPECT_EQ(1,
@@ -385,8 +383,8 @@
   EXPECT_EQ("text", mock_ime_input_context_handler_->last_commit_text());
 
   // Change composition range to include "text".
-  engine_->::input_method::InputMethodEngineBase::SetCompositionRange(
-      context, 0, 4, {}, &error);
+  engine_->chromeos::InputMethodEngineBase::SetCompositionRange(context, 0, 4,
+                                                                {}, &error);
   EXPECT_EQ("", error);
 
   // Disable to commit
diff --git a/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc b/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc
index b977569..90de13f 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc
@@ -37,9 +37,9 @@
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "ui/events/keycodes/keyboard_codes_posix.h"
 
-namespace {
+using chromeos::InputMethodEngineBase;
 
-using input_method::InputMethodEngineBase;
+namespace {
 
 class TestObserver : public InputMethodEngineBase::Observer {
  public:
diff --git a/chrome/browser/chromeos/input_method/personal_info_suggester.cc b/chrome/browser/chromeos/input_method/personal_info_suggester.cc
index 09dc760..5c25831 100644
--- a/chrome/browser/chromeos/input_method/personal_info_suggester.cc
+++ b/chrome/browser/chromeos/input_method/personal_info_suggester.cc
@@ -17,8 +17,6 @@
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 
-using input_method::InputMethodEngineBase;
-
 namespace chromeos {
 
 namespace {
diff --git a/chrome/browser/chromeos/input_method/personal_info_suggester.h b/chrome/browser/chromeos/input_method/personal_info_suggester.h
index a6a6a4d..c56ae13 100644
--- a/chrome/browser/chromeos/input_method/personal_info_suggester.h
+++ b/chrome/browser/chromeos/input_method/personal_info_suggester.h
@@ -71,8 +71,7 @@
   void OnFocus(int context_id) override;
   void OnBlur() override;
   SuggestionStatus HandleKeyEvent(
-      const ::input_method::InputMethodEngineBase::KeyboardEvent& event)
-      override;
+      const InputMethodEngineBase::KeyboardEvent& event) override;
   bool Suggest(const base::string16& text) override;
   void DismissSuggestion() override;
   AssistiveType GetProposeActionType() override;
diff --git a/chrome/browser/chromeos/input_method/personal_info_suggester_unittest.cc b/chrome/browser/chromeos/input_method/personal_info_suggester_unittest.cc
index dbc7620..55137d7 100644
--- a/chrome/browser/chromeos/input_method/personal_info_suggester_unittest.cc
+++ b/chrome/browser/chromeos/input_method/personal_info_suggester_unittest.cc
@@ -109,7 +109,7 @@
   }
 
   void SendKeyboardEvent(std::string key) {
-    ::input_method::InputMethodEngineBase::KeyboardEvent event;
+    InputMethodEngineBase::KeyboardEvent event;
     event.key = key;
     suggester_->HandleKeyEvent(event);
   }
diff --git a/chrome/browser/chromeos/input_method/suggester.h b/chrome/browser/chromeos/input_method/suggester.h
index 8b0c588..e48dfad 100644
--- a/chrome/browser/chromeos/input_method/suggester.h
+++ b/chrome/browser/chromeos/input_method/suggester.h
@@ -28,7 +28,7 @@
   // Called when suggestion is being shown.
   // Returns SuggestionStatus as suggester handles the event.
   virtual SuggestionStatus HandleKeyEvent(
-      const ::input_method::InputMethodEngineBase::KeyboardEvent& event) = 0;
+      const InputMethodEngineBase::KeyboardEvent& event) = 0;
 
   // Check if suggestion should be displayed according to the surrounding text
   // information.
diff --git a/chrome/browser/chromeos/local_search_service/index.cc b/chrome/browser/chromeos/local_search_service/index.cc
index 3088af2..19ba020 100644
--- a/chrome/browser/chromeos/local_search_service/index.cc
+++ b/chrome/browser/chromeos/local_search_service/index.cc
@@ -20,24 +20,10 @@
 using TokenizedStringWithId =
     std::pair<std::string, std::unique_ptr<TokenizedString>>;
 
-// TODO(jiameng): |search_tags| will be removed in the next cl.
-void TokenizeSearchTags(const std::vector<base::string16>& search_tags,
-                        const std::vector<Content>& contents,
+void TokenizeSearchTags(const std::vector<Content>& contents,
                         std::vector<TokenizedStringWithId>* tokenized) {
   DCHECK(tokenized);
 
-  // Only one of them may be non-empty.
-  DCHECK(search_tags.empty() || contents.empty());
-
-  if (!search_tags.empty()) {
-    const std::string empty_content_id;
-    for (const auto& tag : search_tags) {
-      tokenized->push_back(std::make_pair(
-          empty_content_id, std::make_unique<TokenizedString>(tag)));
-    }
-    return;
-  }
-
   for (const auto& content : contents) {
     tokenized->push_back(std::make_pair(
         content.id, std::make_unique<TokenizedString>(content.content)));
@@ -90,9 +76,6 @@
 local_search_service::Content::Content(const Content& content) = default;
 local_search_service::Content::~Content() = default;
 
-local_search_service::Data::Data(const std::string& id,
-                                 const std::vector<base::string16>& search_tags)
-    : id(id), search_tags(search_tags) {}
 local_search_service::Data::Data(
     const std::string& id,
     const std::vector<local_search_service::Content>& contents)
@@ -119,7 +102,7 @@
 
     // If a key already exists, it will overwrite earlier data.
     data_[id] = std::vector<TokenizedStringWithId>();
-    TokenizeSearchTags(item.search_tags, item.contents, &data_[id]);
+    TokenizeSearchTags(item.contents, &data_[id]);
   }
 }
 
@@ -138,25 +121,23 @@
   return num_deleted;
 }
 
-local_search_service::ResponseStatus Index::Find(
-    const base::string16& query,
-    uint32_t max_results,
-    std::vector<local_search_service::Result>* results) {
+ResponseStatus Index::Find(const base::string16& query,
+                           uint32_t max_results,
+                           std::vector<Result>* results) {
   DCHECK(results);
   results->clear();
   if (query.empty()) {
-    return local_search_service::ResponseStatus::kEmptyQuery;
+    return ResponseStatus::kEmptyQuery;
   }
   if (data_.empty()) {
-    return local_search_service::ResponseStatus::kEmptyIndex;
+    return ResponseStatus::kEmptyIndex;
   }
 
   *results = GetSearchResults(query, max_results);
-  return local_search_service::ResponseStatus::kSuccess;
+  return ResponseStatus::kSuccess;
 }
 
-void Index::SetSearchParams(
-    const local_search_service::SearchParams& search_params) {
+void Index::SetSearchParams(const SearchParams& search_params) {
   search_params_ = search_params;
 }
 
@@ -164,10 +145,9 @@
   return search_params_;
 }
 
-std::vector<local_search_service::Result> Index::GetSearchResults(
-    const base::string16& query,
-    uint32_t max_results) const {
-  std::vector<local_search_service::Result> results;
+std::vector<Result> Index::GetSearchResults(const base::string16& query,
+                                            uint32_t max_results) const {
+  std::vector<Result> results;
   const TokenizedString tokenized_query(query);
 
   for (const auto& item : data_) {
@@ -178,7 +158,7 @@
             search_params_.use_prefix_only, search_params_.use_edit_distance,
             search_params_.partial_match_penalty_rate, &relevance_score,
             &positions)) {
-      local_search_service::Result result;
+      Result result;
       result.id = item.first;
       result.score = relevance_score;
       result.positions = positions;
diff --git a/chrome/browser/chromeos/local_search_service/index.h b/chrome/browser/chromeos/local_search_service/index.h
index 6ea4645..d840ea27 100644
--- a/chrome/browser/chromeos/local_search_service/index.h
+++ b/chrome/browser/chromeos/local_search_service/index.h
@@ -37,12 +37,8 @@
   std::string id;
 
   // Data item will be matched between its search tags and query term.
-  // TODO(jiameng): this will be deprecated in the next cl.
-  std::vector<base::string16> search_tags;
   std::vector<Content> contents;
 
-  // TODO(jiameng): this will be deprecated in the next cl.
-  Data(const std::string& id, const std::vector<base::string16>& search_tags);
   Data(const std::string& id, const std::vector<Content>& contents);
   Data();
   Data(const Data& data);
@@ -70,6 +66,11 @@
   // Id of the data.
   std::string id;
   // Relevance score.
+  // Currently only linear map is implemented with fuzzy matching and score will
+  // always be in [0,1]. In the future, when an inverted index is implemented,
+  // the score will not be in this range any more. Client will be able to select
+  // a search backend to use (linear map vs inverted index) and hence client
+  // will be able to expect the range of the scores.
   double score;
   // Position of the matching text.
   // We currently use linear map, which will return one matching content, hence
@@ -110,7 +111,7 @@
 
   // Adds or updates data.
   // IDs of data should not be empty.
-  void AddOrUpdate(const std::vector<local_search_service::Data>& data);
+  void AddOrUpdate(const std::vector<Data>& data);
 
   // Deletes data with |ids| and returns number of items deleted.
   // If an id doesn't exist in the Index, no operation will be done.
@@ -122,20 +123,18 @@
   // For each data in the index, we return the 1st search tag that matches
   // the query (i.e. above the threshold). Client should put the most
   // important search tag first when registering the data in the index.
-  local_search_service::ResponseStatus Find(
-      const base::string16& query,
-      uint32_t max_results,
-      std::vector<local_search_service::Result>* results);
+  ResponseStatus Find(const base::string16& query,
+                      uint32_t max_results,
+                      std::vector<Result>* results);
 
-  void SetSearchParams(const local_search_service::SearchParams& search_params);
+  void SetSearchParams(const SearchParams& search_params);
 
   SearchParams GetSearchParamsForTesting();
 
  private:
   // Returns all search results for a given query.
-  std::vector<local_search_service::Result> GetSearchResults(
-      const base::string16& query,
-      uint32_t max_results) const;
+  std::vector<Result> GetSearchResults(const base::string16& query,
+                                       uint32_t max_results) const;
 
   // A map from key to a vector of (tag-id, tokenized tag).
   std::map<
@@ -144,7 +143,7 @@
       data_;
 
   // Search parameters.
-  local_search_service::SearchParams search_params_;
+  SearchParams search_params_;
 
   base::WeakPtrFactory<Index> weak_ptr_factory_{this};
 };
diff --git a/chrome/browser/chromeos/local_search_service/index_unittest.cc b/chrome/browser/chromeos/local_search_service/index_unittest.cc
index 18c4d960..ce55234 100644
--- a/chrome/browser/chromeos/local_search_service/index_unittest.cc
+++ b/chrome/browser/chromeos/local_search_service/index_unittest.cc
@@ -11,7 +11,6 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/local_search_service/index.h"
-#include "chrome/browser/chromeos/local_search_service/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace local_search_service {
@@ -182,9 +181,9 @@
 }
 
 TEST_F(IndexTest, ResultFound) {
-  // Register search tags but not contents to test backward compatibility.
-  const std::map<std::string, std::vector<std::string>> data_to_register = {
-      {"id1", {"id1", "tag1a", "tag1b"}}, {"xyz", {"xyz"}}};
+  const std::map<std::string, std::vector<ContentWithId>> data_to_register = {
+      {"id1", {{"cid1", "id1"}, {"cid2", "tag1a"}, {"cid3", "tag1b"}}},
+      {"xyz", {{"cid4", "xyz"}}}};
   std::vector<Data> data = CreateTestData(data_to_register);
   EXPECT_EQ(data.size(), 2u);
 
@@ -192,7 +191,7 @@
   EXPECT_EQ(index_.GetSize(), 2u);
 
   // Find result with query "id1". It returns an exact match.
-  const std::vector<ResultWithIds> expected_results = {{"id1", {""}}};
+  const std::vector<ResultWithIds> expected_results = {{"id1", {"cid1"}}};
   FindAndCheckResults(&index_, "id1",
                       /*max_results=*/-1, ResponseStatus::kSuccess,
                       expected_results);
diff --git a/chrome/browser/chromeos/local_search_service/local_search_service.cc b/chrome/browser/chromeos/local_search_service/local_search_service.cc
index b4aed8bb..60e8eb2 100644
--- a/chrome/browser/chromeos/local_search_service/local_search_service.cc
+++ b/chrome/browser/chromeos/local_search_service/local_search_service.cc
@@ -14,7 +14,7 @@
 
 LocalSearchService::~LocalSearchService() = default;
 
-Index* LocalSearchService::GetIndex(local_search_service::IndexId index_id) {
+Index* LocalSearchService::GetIndex(IndexId index_id) {
   auto it = indices_.find(index_id);
   if (it == indices_.end())
     it = indices_.emplace(index_id, std::make_unique<Index>()).first;
diff --git a/chrome/browser/chromeos/local_search_service/local_search_service.h b/chrome/browser/chromeos/local_search_service/local_search_service.h
index 838de64..e8511cc 100644
--- a/chrome/browser/chromeos/local_search_service/local_search_service.h
+++ b/chrome/browser/chromeos/local_search_service/local_search_service.h
@@ -26,10 +26,10 @@
   LocalSearchService(const LocalSearchService&) = delete;
   LocalSearchService& operator=(const LocalSearchService&) = delete;
 
-  Index* GetIndex(local_search_service::IndexId index_id);
+  Index* GetIndex(IndexId index_id);
 
  private:
-  std::map<local_search_service::IndexId, std::unique_ptr<Index>> indices_;
+  std::map<IndexId, std::unique_ptr<Index>> indices_;
 };
 
 }  // namespace local_search_service
diff --git a/chrome/browser/chromeos/local_search_service/test_utils.cc b/chrome/browser/chromeos/local_search_service/test_utils.cc
deleted file mode 100644
index fa1d9be5..0000000
--- a/chrome/browser/chromeos/local_search_service/test_utils.cc
+++ /dev/null
@@ -1,66 +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 "chrome/browser/chromeos/local_search_service/test_utils.h"
-
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace local_search_service {
-
-namespace {
-
-std::vector<base::string16> MultiUTF8ToUTF16(
-    const std::vector<std::string>& input) {
-  std::vector<base::string16> output;
-  for (const auto& str : input) {
-    output.push_back(base::UTF8ToUTF16(str));
-  }
-  return output;
-}
-
-}  // namespace
-
-std::vector<Data> CreateTestData(
-    const std::map<std::string, std::vector<std::string>>& input) {
-  std::vector<Data> output;
-  for (const auto& item : input) {
-    const std::vector<base::string16> tags = MultiUTF8ToUTF16(item.second);
-    const Data data(item.first, tags);
-    output.push_back(data);
-  }
-  return output;
-}
-
-void FindAndCheck(Index* index,
-                  std::string query,
-                  int32_t max_results,
-                  ResponseStatus expected_status,
-                  const std::vector<std::string>& expected_result_ids) {
-  DCHECK(index);
-
-  std::vector<Result> results;
-  auto status = index->Find(base::UTF8ToUTF16(query), max_results, &results);
-
-  EXPECT_EQ(status, expected_status);
-
-  if (!results.empty()) {
-    // If results are returned, check size and values match the expected.
-    EXPECT_EQ(results.size(), expected_result_ids.size());
-    for (size_t i = 0; i < results.size(); ++i) {
-      EXPECT_EQ(results[i].id, expected_result_ids[i]);
-      // Scores should be non-increasing.
-      if (i < results.size() - 1) {
-        EXPECT_GE(results[i].score, results[i + 1].score);
-      }
-    }
-    return;
-  }
-
-  // If no results are returned, expected ids should be empty.
-  EXPECT_TRUE(expected_result_ids.empty());
-}
-
-}  // namespace local_search_service
diff --git a/chrome/browser/chromeos/local_search_service/test_utils.h b/chrome/browser/chromeos/local_search_service/test_utils.h
deleted file mode 100644
index 2b497311..0000000
--- a/chrome/browser/chromeos/local_search_service/test_utils.h
+++ /dev/null
@@ -1,31 +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 CHROME_BROWSER_CHROMEOS_LOCAL_SEARCH_SERVICE_TEST_UTILS_H_
-#define CHROME_BROWSER_CHROMEOS_LOCAL_SEARCH_SERVICE_TEST_UTILS_H_
-
-#include <map>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "chrome/browser/chromeos/local_search_service/index.h"
-
-namespace local_search_service {
-
-// Creates test data to be registered to the index. |input| is a map from
-// id to search-tags.
-std::vector<Data> CreateTestData(
-    const std::map<std::string, std::vector<std::string>>& input);
-
-// Finds item for |query| from |index| and checks their ids are those in
-// |expected_result_ids|.
-void FindAndCheck(Index* index,
-                  std::string query,
-                  int32_t max_results,
-                  ResponseStatus expected_status,
-                  const std::vector<std::string>& expected_result_ids);
-}  // namespace local_search_service
-
-#endif  // CHROME_BROWSER_CHROMEOS_LOCAL_SEARCH_SERVICE_TEST_UTILS_H_
diff --git a/chrome/browser/chromeos/login/app_launch_controller.cc b/chrome/browser/chromeos/login/app_launch_controller.cc
index 09e11d7..615c26939 100644
--- a/chrome/browser/chromeos/login/app_launch_controller.cc
+++ b/chrome/browser/chromeos/login/app_launch_controller.cc
@@ -39,8 +39,7 @@
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/notification_service.h"
-#include "extensions/browser/app_window/app_window.h"
-#include "extensions/browser/app_window/app_window_registry.h"
+#include "extensions/common/features/feature_session_type.h"
 #include "services/network/public/cpp/network_connection_tracker.h"
 #include "ui/base/ui_base_features.h"
 
@@ -100,48 +99,6 @@
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
-// AppLaunchController::AppWindowWatcher
-
-class AppLaunchController::AppWindowWatcher
-    : public extensions::AppWindowRegistry::Observer {
- public:
-  explicit AppWindowWatcher(AppLaunchController* controller,
-                            const std::string& app_id)
-      : controller_(controller),
-        app_id_(app_id),
-        window_registry_(
-            extensions::AppWindowRegistry::Get(controller->profile_)) {
-    if (!window_registry_->GetAppWindowsForApp(app_id).empty()) {
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::BindOnce(&AppWindowWatcher::NotifyAppWindowCreated,
-                                    weak_factory_.GetWeakPtr()));
-      return;
-    } else {
-      window_registry_->AddObserver(this);
-    }
-  }
-  ~AppWindowWatcher() override { window_registry_->RemoveObserver(this); }
-
- private:
-  // extensions::AppWindowRegistry::Observer overrides:
-  void OnAppWindowAdded(extensions::AppWindow* app_window) override {
-    if (app_window->extension_id() == app_id_) {
-      window_registry_->RemoveObserver(this);
-      NotifyAppWindowCreated();
-    }
-  }
-
-  void NotifyAppWindowCreated() { controller_->OnAppWindowCreated(); }
-
-  AppLaunchController* controller_;
-  std::string app_id_;
-  extensions::AppWindowRegistry* window_registry_;
-  base::WeakPtrFactory<AppWindowWatcher> weak_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(AppWindowWatcher);
-};
-
-////////////////////////////////////////////////////////////////////////////////
 // AppLaunchController
 
 AppLaunchController::AppLaunchController(const std::string& app_id,
@@ -511,9 +468,6 @@
     app_launch_splash_screen_view_->UpdateAppLaunchState(
         AppLaunchSplashScreenView::APP_LAUNCH_STATE_WAITING_APP_WINDOW);
   }
-
-  DCHECK(!app_window_watcher_);
-  app_window_watcher_.reset(new AppWindowWatcher(this, app_id_));
 }
 
 void AppLaunchController::OnLaunchFailed(KioskAppLaunchError::Error error) {
diff --git a/chrome/browser/chromeos/login/app_launch_controller.h b/chrome/browser/chromeos/login/app_launch_controller.h
index 5dc0b0f..2c0cb9da 100644
--- a/chrome/browser/chromeos/login/app_launch_controller.h
+++ b/chrome/browser/chromeos/login/app_launch_controller.h
@@ -70,16 +70,10 @@
   static void SetBlockAppLaunchForTesting(bool block);
 
  private:
-  // A class to watch app window creation.
-  class AppWindowWatcher;
-
   void ClearNetworkWaitTimer();
   void CleanUp();
   void OnNetworkWaitTimedout();
 
-  // Callback of AppWindowWatcher to notify an app window is created.
-  void OnAppWindowCreated();
-
   // Whether the network could be configured during launching.
   bool CanConfigureNetwork();
 
@@ -107,6 +101,7 @@
   void OnReadyToLaunch() override;
   void OnLaunchSucceeded() override;
   void OnLaunchFailed(KioskAppLaunchError::Error error) override;
+  void OnAppWindowCreated() override;
   bool IsShowingNetworkConfigScreen() override;
 
   // AppLaunchSigninScreen::Delegate overrides:
@@ -120,7 +115,6 @@
   std::unique_ptr<KioskProfileLoader> kiosk_profile_loader_;
   std::unique_ptr<StartupAppLauncher> startup_app_launcher_;
   std::unique_ptr<AppLaunchSigninScreen> signin_screen_;
-  std::unique_ptr<AppWindowWatcher> app_window_watcher_;
 
   bool launcher_ready_ = false;
   bool cleaned_up_ = false;
diff --git a/chrome/browser/chromeos/login/screens/sync_consent_browsertest.cc b/chrome/browser/chromeos/login/screens/sync_consent_browsertest.cc
index a0d13ee..a514eda 100644
--- a/chrome/browser/chromeos/login/screens/sync_consent_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/sync_consent_browsertest.cc
@@ -314,6 +314,9 @@
   histogram_tester_.ExpectTotalCount(
       "OOBE.StepCompletionTimeByExitReason.Sync-consent.Next", 1);
   histogram_tester_.ExpectTotalCount("OOBE.StepCompletionTime.Sync-consent", 1);
+  histogram_tester_.ExpectUniqueSample(
+      "OOBE.SyncConsentScreen.Behavior",
+      SyncConsentScreen::SyncScreenBehavior::kShow, 1);
 }
 
 class SyncConsentTestWithParams
@@ -473,6 +476,12 @@
   histogram_tester_.ExpectTotalCount(
       "OOBE.StepCompletionTimeByExitReason.Sync-consent.Next", 1);
   histogram_tester_.ExpectTotalCount("OOBE.StepCompletionTime.Sync-consent", 1);
+  histogram_tester_.ExpectUniqueSample(
+      "OOBE.SyncConsentScreen.Behavior",
+      SyncConsentScreen::SyncScreenBehavior::kShow, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "OOBE.SyncConsentScreen.UserChoice",
+      SyncConsentScreenHandler::UserChoice::kAccepted, 1);
 
   // Dialog is completed.
   EXPECT_TRUE(prefs->GetBoolean(chromeos::prefs::kSyncOobeCompleted));
@@ -513,6 +522,13 @@
   EXPECT_FALSE(settings->IsSyncEverythingEnabled());
   EXPECT_TRUE(settings->GetSelectedTypes().Empty());
 
+  histogram_tester_.ExpectUniqueSample(
+      "OOBE.SyncConsentScreen.Behavior",
+      SyncConsentScreen::SyncScreenBehavior::kShow, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "OOBE.SyncConsentScreen.UserChoice",
+      SyncConsentScreenHandler::UserChoice::kDeclined, 1);
+
   // Dialog is completed.
   EXPECT_TRUE(prefs->GetBoolean(chromeos::prefs::kSyncOobeCompleted));
 }
@@ -575,6 +591,10 @@
   // Dialog is completed.
   PrefService* prefs = ProfileManager::GetPrimaryUserProfile()->GetPrefs();
   EXPECT_TRUE(prefs->GetBoolean(chromeos::prefs::kSyncOobeCompleted));
+
+  histogram_tester_.ExpectUniqueSample(
+      "OOBE.SyncConsentScreen.Behavior",
+      SyncConsentScreen::SyncScreenBehavior::kSkipAndEnableSync, 1);
 }
 
 IN_PROC_BROWSER_TEST_F(SyncConsentSplitSettingsSyncTest,
@@ -596,6 +616,10 @@
   // Dialog is completed.
   PrefService* prefs = ProfileManager::GetPrimaryUserProfile()->GetPrefs();
   EXPECT_TRUE(prefs->GetBoolean(chromeos::prefs::kSyncOobeCompleted));
+
+  histogram_tester_.ExpectUniqueSample(
+      "OOBE.SyncConsentScreen.Behavior",
+      SyncConsentScreen::SyncScreenBehavior::kSkip, 1);
 }
 
 // Tests for Active Directory accounts, which skip the dialog because they do
@@ -640,6 +664,9 @@
   histogram_tester_.ExpectTotalCount(
       "OOBE.StepCompletionTimeByExitReason.Sync-consent.Next", 0);
   histogram_tester_.ExpectTotalCount("OOBE.StepCompletionTime.Sync-consent", 0);
+  histogram_tester_.ExpectUniqueSample(
+      "OOBE.SyncConsentScreen.Behavior",
+      SyncConsentScreen::SyncScreenBehavior::kSkip, 1);
 }
 
 // Tests that the SyncConsent screen performs a timezone request so that
diff --git a/chrome/browser/chromeos/login/screens/sync_consent_screen.cc b/chrome/browser/chromeos/login/screens/sync_consent_screen.cc
index ad647b01..71229ca2 100644
--- a/chrome/browser/chromeos/login/screens/sync_consent_screen.cc
+++ b/chrome/browser/chromeos/login/screens/sync_consent_screen.cc
@@ -117,6 +117,8 @@
   DCHECK(profile_);
   // Always set completed, even if the dialog was skipped (e.g. by policy).
   profile_->GetPrefs()->SetBoolean(chromeos::prefs::kSyncOobeCompleted, true);
+  // Record whether the dialog was shown, skipped, etc.
+  base::UmaHistogramEnumeration("OOBE.SyncConsentScreen.Behavior", behavior_);
   exit_callback_.Run(result);
 }
 
@@ -180,16 +182,18 @@
   Finish(Result::NEXT);
 }
 
-void SyncConsentScreen::OnAcceptAndContinue(
+void SyncConsentScreen::OnContinue(
     const std::vector<int>& consent_description,
     int consent_confirmation,
-    bool enable_sync) {
+    SyncConsentScreenHandler::UserChoice choice) {
   DCHECK(chromeos::features::IsSplitSettingsSyncEnabled());
   if (is_hidden())
     return;
+  base::UmaHistogramEnumeration("OOBE.SyncConsentScreen.UserChoice", choice);
   // Record that the user saw the consent text, regardless of which features
   // they chose to enable.
   RecordConsent(CONSENT_GIVEN, consent_description, consent_confirmation);
+  bool enable_sync = choice == SyncConsentScreenHandler::UserChoice::kAccepted;
   UpdateSyncSettings(enable_sync);
   Finish(Result::NEXT);
 }
diff --git a/chrome/browser/chromeos/login/screens/sync_consent_screen.h b/chrome/browser/chromeos/login/screens/sync_consent_screen.h
index 18deaf9..da69282 100644
--- a/chrome/browser/chromeos/login/screens/sync_consent_screen.h
+++ b/chrome/browser/chromeos/login/screens/sync_consent_screen.h
@@ -26,15 +26,17 @@
 // sign-in flow.
 class SyncConsentScreen : public BaseScreen,
                           public syncer::SyncServiceObserver {
- private:
+ public:
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused. Public for testing.
   enum class SyncScreenBehavior {
-    kUnknown,            // Not yet known.
-    kShow,               // Screen should be shown.
-    kSkip,               // Skip screen, don't change sync state.
-    kSkipAndEnableSync,  // Skip screen and enable sync.
+    kUnknown = 0,            // Not yet known.
+    kShow = 1,               // Screen should be shown.
+    kSkip = 2,               // Skip screen, don't change sync state.
+    kSkipAndEnableSync = 3,  // Skip screen and enable sync.
+    kMaxValue = kSkipAndEnableSync
   };
 
- public:
   enum ConsentGiven { CONSENT_NOT_GIVEN, CONSENT_GIVEN };
 
   enum class Result { NEXT, NOT_APPLICABLE };
@@ -87,9 +89,9 @@
                               const int consent_confirmation);
 
   // Reacts to "Yes, I'm in" and "No, thanks".
-  void OnAcceptAndContinue(const std::vector<int>& consent_description,
-                           int consent_confirmation,
-                           bool enable_sync);
+  void OnContinue(const std::vector<int>& consent_description,
+                  int consent_confirmation,
+                  SyncConsentScreenHandler::UserChoice choice);
 
   // Configures OS sync and browser sync.
   void UpdateSyncSettings(bool enable_sync);
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_installer.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_installer.cc
index 3ab3915..0a164ff 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_installer.cc
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_installer.cc
@@ -283,7 +283,8 @@
     return;
   }
 
-  using_drive_download_service_ = IsDriveUrl(url);
+  base::Optional<std::string> drive_id = GetIdFromDriveUrl(url);
+  using_drive_download_service_ = drive_id.has_value();
 
   if (using_drive_download_service_) {
     if (!drive_download_service_) {
@@ -293,7 +294,7 @@
       drive_download_service_->ResetState();
     }
 
-    drive_download_service_->StartDownload(GetIdFromDriveUrl(url));
+    drive_download_service_->StartDownload(drive_id.value());
   } else {
     download_service_->StartDownload(GetDownloadParams(url));
   }
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_pref_names.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_pref_names.cc
index f9d54ef01..ee76da5 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_pref_names.cc
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_pref_names.cc
@@ -40,6 +40,11 @@
 // GuestOsEngagementMetrics.
 const char kEngagementPrefsPrefix[] = "plugin_vm.metrics";
 
+// A boolean preference indicating whether data collection performed by PluginVm
+// is allowed by the corresponding boolean user policy.
+const char kPluginVmDataCollectionAllowed[] =
+    "plugin_vm.data_collection_allowed";
+
 void RegisterProfilePrefs(PrefRegistrySimple* registry) {
   registry->RegisterBooleanPref(kPluginVmAllowed, false);
   registry->RegisterDictionaryPref(kPluginVmImage);
@@ -50,6 +55,7 @@
   registry->RegisterBooleanPref(kPluginVmPrintersAllowed, true);
   registry->RegisterBooleanPref(kPluginVmCameraSharing, false);
   registry->RegisterStringPref(kPluginVmUserId, std::string());
+  registry->RegisterBooleanPref(kPluginVmDataCollectionAllowed, false);
 
   guest_os::prefs::RegisterEngagementProfilePrefs(registry,
                                                   kEngagementPrefsPrefix);
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_pref_names.h b/chrome/browser/chromeos/plugin_vm/plugin_vm_pref_names.h
index af6789c..1438d7ed6 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_pref_names.h
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_pref_names.h
@@ -17,6 +17,7 @@
 extern const char kPluginVmCameraSharing[];
 extern const char kPluginVmUserId[];
 extern const char kEngagementPrefsPrefix[];
+extern const char kPluginVmDataCollectionAllowed[];
 
 void RegisterProfilePrefs(PrefRegistrySimple* registry);
 
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_util.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_util.cc
index 9ab55e6..d821e40 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_util.cc
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_util.cc
@@ -10,6 +10,8 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/observer_list.h"
+#include "base/strings/pattern.h"
+#include "base/strings/string_util.h"
 #include "base/task/post_task.h"
 #include "base/task/thread_pool.h"
 #include "chrome/browser/chromeos/plugin_vm/plugin_vm_drive_image_download_service.h"
@@ -28,6 +30,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "google_apis/drive/drive_api_error_codes.h"
+#include "net/base/url_util.h"
 
 namespace plugin_vm {
 
@@ -184,25 +187,34 @@
       base::BindOnce(std::move(log_file_deletion_if_failed)));
 }
 
-// TODO(muhamedp): Update if a different url format is ultimately chosen.
-bool IsDriveUrl(const GURL& url) {
-  const std::string url_base = "https://drive.google.com/open";
-  const std::string& spec = url.spec();
-  return spec.find(url_base) == 0 && spec.find("id=") < (spec.length() - 3);
-}
-
-// TODO(muhamedp): Update if a different url format is ultimately chosen.
-std::string GetIdFromDriveUrl(const GURL& url) {
+base::Optional<std::string> GetIdFromDriveUrl(const GURL& url) {
   const std::string& spec = url.spec();
 
-  const size_t id_start = spec.find("id=") + 3;
-  // In case there are other GET parameters after the id.
-  const size_t first_ampersand = spec.find('&', id_start);
+  const std::string kOpenUrlBase = "https://drive.google.com/open?";
+  if (base::StartsWith(spec, kOpenUrlBase,
+                       base::CompareCase::INSENSITIVE_ASCII)) {
+    // e.g. https://drive.google.com/open?id=[ID]
+    std::string id;
+    if (!net::GetValueForKeyInQuery(url, "id", &id))
+      return base::nullopt;
+    return id;
+  }
 
-  if (first_ampersand == std::string::npos)
-    return spec.substr(id_start);
-  else
-    return spec.substr(id_start, first_ampersand - id_start);
+  // These will match some invalid URLs, which is fine.
+  const std::string kViewUrlPatternWithDomain =
+      "https://drive.google.com/a/*/file/d/*/view*";
+  const std::string kViewUrlPatternWithoutDomain =
+      "https://drive.google.com/file/d/*/view*";
+  if (base::MatchPattern(spec, kViewUrlPatternWithDomain) ||
+      base::MatchPattern(spec, kViewUrlPatternWithoutDomain)) {
+    // e.g. https://drive.google.com/a/example.org/file/d/[ID]/view?usp=sharing
+    // or https://drive.google.com/file/d/[ID]/view?usp=sharing
+    size_t id_end = spec.find("/view");
+    size_t id_start = spec.rfind('/', id_end - 1) + 1;
+    return spec.substr(id_start, id_end - id_start);
+  }
+
+  return base::nullopt;
 }
 
 PluginVmPolicySubscription::PluginVmPolicySubscription(
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_util.h b/chrome/browser/chromeos/plugin_vm/plugin_vm_util.h
index d7503bbff..9684317 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_util.h
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_util.h
@@ -10,6 +10,7 @@
 
 #include "base/callback.h"
 #include "base/observer_list_types.h"
+#include "base/optional.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
@@ -95,8 +96,9 @@
 // Used to clean up the Plugin VM Drive download directory if it did not get
 // removed when it should have, perhaps due to a crash.
 void RemoveDriveDownloadDirectoryIfExists();
-bool IsDriveUrl(const GURL& url);
-std::string GetIdFromDriveUrl(const GURL& url);
+
+// Returns nullopt if not a drive URL.
+base::Optional<std::string> GetIdFromDriveUrl(const GURL& url);
 
 // A subscription for changes to PluginVm policy that may affect
 // IsPluginVmAllowedForProfile.
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_util_unittest.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_util_unittest.cc
index 1964ab93..a686e97d 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_util_unittest.cc
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_util_unittest.cc
@@ -19,9 +19,6 @@
 
 namespace plugin_vm {
 
-const char kBaseDriveUrl[] = "https://drive.google.com/open?id=";
-const char kDriveFileId[] = "Yxhi5BDTxsEl9onT8AunH4o_tkKviFGjY";
-const char kDriveExtraParam[] = "&foobar=barfoo";
 
 class PluginVmUtilTest : public testing::Test {
  public:
@@ -123,30 +120,48 @@
                                            false);
 }
 
-TEST_F(PluginVmUtilTest, DriveLinkDetection) {
-  std::string base_url(kBaseDriveUrl);
-  std::string file_id(kDriveFileId);
-
-  EXPECT_TRUE(IsDriveUrl(GURL(base_url + file_id)));
-  EXPECT_TRUE(IsDriveUrl(
-      GURL(base_url + file_id + kDriveExtraParam + kDriveExtraParam)));
-
-  EXPECT_FALSE(IsDriveUrl(GURL("https://othersite.com?id=" + file_id)));
-  EXPECT_FALSE(
-      IsDriveUrl(GURL("https://drive.google.com.othersite.com?id=" + file_id)));
-  EXPECT_FALSE(IsDriveUrl(GURL(base_url)));
+TEST_F(PluginVmUtilTest, DriveUrlNonMatches) {
+  EXPECT_EQ(base::nullopt,
+            GetIdFromDriveUrl(GURL(
+                "http://192.168.0.2?id=Yxhi5BDTxsEl9onT8AunH4o_tkKviFGjY")));
+  EXPECT_EQ(base::nullopt,
+            GetIdFromDriveUrl(
+                GURL("https://drive.notgoogle.com/open?id=someSortOfId123")));
+  EXPECT_EQ(base::nullopt,
+            GetIdFromDriveUrl(GURL(
+                "https://site.com/a/site.com/file/d/definitelyNotDrive/view")));
+  EXPECT_EQ(
+      base::nullopt,
+      GetIdFromDriveUrl(GURL("file:///home/chronos/user/Downloads/file.zip")));
+  EXPECT_EQ(base::nullopt,
+            GetIdFromDriveUrl(GURL("http://drive.google.com/open?id=fancyId")));
 }
 
-TEST_F(PluginVmUtilTest, DriveLinkIdExtraction) {
-  std::string base_url(kBaseDriveUrl);
-  std::string file_id(kDriveFileId);
+TEST_F(PluginVmUtilTest, DriveUrlPatternWithOpen) {
+  EXPECT_EQ("fancyId", GetIdFromDriveUrl(
+                           GURL("https://drive.google.com/open?id=fancyId")));
+  EXPECT_EQ("fancyId2",
+            GetIdFromDriveUrl(
+                GURL("https://drive.google.com/open?id=fancyId2&foo=bar")));
+  EXPECT_EQ(
+      "SomeCoolId000",
+      GetIdFromDriveUrl(GURL(
+          "https://drive.google.com/open?bar=foo&id=SomeCoolId000&foo=bar")));
+}
 
-  EXPECT_EQ(GetIdFromDriveUrl(GURL(base_url + file_id)), file_id);
-  EXPECT_EQ(GetIdFromDriveUrl(GURL(base_url + file_id + kDriveExtraParam)),
-            file_id);
-  EXPECT_EQ(GetIdFromDriveUrl(
-                GURL(base_url + file_id + kDriveExtraParam + kDriveExtraParam)),
-            file_id);
+TEST_F(PluginVmUtilTest, DriveUrlPatternWithView) {
+  EXPECT_EQ("Id123",
+            GetIdFromDriveUrl(GURL("https://drive.google.com/a/google.com/file/"
+                                   "d/Id123/view?usp=sharing")));
+  EXPECT_EQ("PluginVmIsCool",
+            GetIdFromDriveUrl(GURL("https://drive.google.com/a/fancydomain.org/"
+                                   "file/d/PluginVmIsCool/view")));
+
+  EXPECT_EQ("hello",
+            GetIdFromDriveUrl(GURL(
+                "https://drive.google.com/file/d/hello/view?usp=sharing")));
+  EXPECT_EQ("w-r-d", GetIdFromDriveUrl(
+                         GURL("https://drive.google.com/file/d/w-r-d/view")));
 }
 
 }  // namespace plugin_vm
diff --git a/chrome/browser/chromeos/policy/fuzzer/policy_fuzzer.cc b/chrome/browser/chromeos/policy/fuzzer/policy_fuzzer.cc
index 0b785a4..4fd22e0 100644
--- a/chrome/browser/chromeos/policy/fuzzer/policy_fuzzer.cc
+++ b/chrome/browser/chromeos/policy/fuzzer/policy_fuzzer.cc
@@ -8,26 +8,48 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/policy/device_policy_decoder_chromeos.h"
 #include "chrome/browser/chromeos/policy/fuzzer/policy_fuzzer.pb.h"
+#include "chrome/browser/policy/configuration_policy_handler_list_factory.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
+#include "components/policy/core/browser/configuration_policy_handler_list.h"
+#include "components/policy/core/browser/policy_conversions_client.h"
+#include "components/policy/core/browser/policy_error_map.h"
+#include "components/policy/core/common/chrome_schema.h"
 #include "components/policy/core/common/cloud/cloud_external_data_manager.h"
 #include "components/policy/core/common/external_data_manager.h"
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/core/common/policy_proto_decoders.h"
 #include "components/policy/core/common/policy_types.h"
+#include "components/prefs/pref_value_map.h"
 #include "testing/libfuzzer/proto/lpm_interface.h"
 
 namespace policy {
 
-bool FuzzTestInitializer() {
-  logging::SetMinLogLevel(logging::LOG_FATAL);
-  base::CommandLine::Init(0, nullptr);
-  chromeos::DBusThreadManager::Initialize();
-  return true;
+namespace {
+
+struct Environment {
+  Environment() {
+    logging::SetMinLogLevel(logging::LOG_FATAL);
+    base::CommandLine::Init(0, nullptr);
+    chromeos::DBusThreadManager::Initialize();
+    policy_handler_list = BuildHandlerList(GetChromeSchema());
+  }
+
+  std::unique_ptr<ConfigurationPolicyHandlerList> policy_handler_list;
+};
+
+void CheckPolicyToPrefTranslation(const PolicyMap& policy_map,
+                                  const Environment& environment) {
+  PrefValueMap prefs;
+  PolicyErrorMap errors;
+  DeprecatedPoliciesSet deprecated_policies;
+  environment.policy_handler_list->ApplyPolicySettings(
+      policy_map, &prefs, &errors, &deprecated_policies);
 }
 
+}  // namespace
+
 DEFINE_PROTO_FUZZER(const PolicyFuzzerProto& proto) {
-  static bool initialized = FuzzTestInitializer();
-  CHECK(initialized);
+  static Environment environment;
 
   if (proto.has_chrome_device_settings()) {
     const enterprise_management::ChromeDeviceSettingsProto&
@@ -43,6 +65,8 @@
       CHECK_EQ(entry.scope, POLICY_SCOPE_MACHINE)
           << "Policy " << policy_name << " has not machine scope";
     }
+
+    CheckPolicyToPrefTranslation(policy_map, environment);
   }
 
   if (proto.has_cloud_policy_settings()) {
@@ -61,6 +85,8 @@
       CHECK_EQ(entry.scope, POLICY_SCOPE_USER)
           << "Policy " << policy_name << " has not user scope";
     }
+
+    CheckPolicyToPrefTranslation(policy_map, environment);
   }
 }
 
diff --git a/chrome/browser/component_updater/vr_assets_component_installer.cc b/chrome/browser/component_updater/vr_assets_component_installer.cc
index c8242845..d3886d9 100644
--- a/chrome/browser/component_updater/vr_assets_component_installer.cc
+++ b/chrome/browser/component_updater/vr_assets_component_installer.cc
@@ -19,7 +19,6 @@
 #include "base/version.h"
 #include "build/build_config.h"
 #include "chrome/browser/vr/assets_loader.h"
-#include "chrome/browser/vr/metrics/metrics_helper.h"
 #include "chrome/browser/vr/vr_buildflags.h"
 #include "components/component_updater/component_updater_paths.h"
 #include "components/component_updater/component_updater_service.h"
@@ -104,7 +103,6 @@
 // static
 void VrAssetsComponentInstallerPolicy::OnRegisteredComponent(
     ComponentUpdateService* cus) {
-  vr::AssetsLoader::GetInstance()->GetMetricsHelper()->OnRegisteredComponent();
   VLOG(1) << "Registered VR assets component";
   registration_pending_ = false;
   registered_component_ = true;
@@ -137,8 +135,6 @@
     const base::FilePath& install_dir) const {
   auto* version_value = manifest.FindKey("version");
   if (!version_value || !version_value->is_string()) {
-    vr::AssetsLoader::GetInstance()->GetMetricsHelper()->OnComponentUpdated(
-        vr::AssetsComponentUpdateStatus::kInvalid, base::nullopt);
     return false;
   }
 
@@ -146,16 +142,12 @@
   base::Version version(version_string);
   if (!version.IsValid() || version.components().size() != 2 ||
       !base::PathExists(install_dir)) {
-    vr::AssetsLoader::GetInstance()->GetMetricsHelper()->OnComponentUpdated(
-        vr::AssetsComponentUpdateStatus::kInvalid, base::nullopt);
     return false;
   }
 
   if (version.components()[0] > vr::kTargetMajorVrAssetsComponentVersion) {
     // Component needs to be downgraded. Differential downgrades are not
     // supported. Just delete this component version.
-    vr::AssetsLoader::GetInstance()->GetMetricsHelper()->OnComponentUpdated(
-        vr::AssetsComponentUpdateStatus::kIncompatible, version);
     return false;
   }
 
@@ -169,8 +161,6 @@
   if (version.components()[0] < vr::kMinMajorVrAssetsComponentVersion) {
     // Don't propagate component readiness and wait until differential update
     // delivers compatible component version.
-    vr::AssetsLoader::GetInstance()->GetMetricsHelper()->OnComponentUpdated(
-        vr::AssetsComponentUpdateStatus::kIncompatible, version);
     return;
   }
   vr::AssetsLoader::GetInstance()->OnComponentReady(version, install_dir,
diff --git a/chrome/browser/content_settings/generated_cookie_prefs.h b/chrome/browser/content_settings/generated_cookie_prefs.h
index efd4080..7fc3add 100644
--- a/chrome/browser/content_settings/generated_cookie_prefs.h
+++ b/chrome/browser/content_settings/generated_cookie_prefs.h
@@ -17,10 +17,8 @@
 extern const char kCookieSessionOnly[];
 extern const char kCookiePrimarySetting[];
 
-// Must be kept in sync with the CookiesControl enum located in
+// Must be kept in sync with the enum of the same name located in
 // chrome/browser/resources/settings/privacy_page/cookies_page.js
-// TODO(crbug.com/1063265): Rename JS enum to match this one when the generated
-//    preference is used in production code.
 enum class CookiePrimarySetting {
   ALLOW_ALL,
   BLOCK_THIRD_PARTY_INCOGNITO,
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index 1248872..2ffe7715 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -105,6 +105,8 @@
     "DevTools.IssuesPanelOpenedFrom";
 static const char kDevToolsKeybindSetSettingChanged[] =
     "DevTools.KeybindSetSettingChanged";
+static const char kDevToolsDualScreenDeviceEmulatedHistogram[] =
+    "DevTools.DualScreenDeviceEmulated";
 
 static const char kRemotePageActionInspect[] = "inspect";
 static const char kRemotePageActionReload[] = "reload";
@@ -1239,15 +1241,17 @@
   // Each histogram name must follow a different code path in
   // order to UMA_HISTOGRAM_EXACT_LINEAR work correctly.
   if (name == kDevToolsActionTakenHistogram)
-    UMA_HISTOGRAM_EXACT_LINEAR(name, sample, boundary_value);
+    base::UmaHistogramExactLinear(name, sample, boundary_value);
   else if (name == kDevToolsPanelShownHistogram)
-    UMA_HISTOGRAM_EXACT_LINEAR(name, sample, boundary_value);
+    base::UmaHistogramExactLinear(name, sample, boundary_value);
   else if (name == kDevToolsKeyboardShortcutFiredHistogram)
-    UMA_HISTOGRAM_EXACT_LINEAR(name, sample, boundary_value);
+    base::UmaHistogramExactLinear(name, sample, boundary_value);
   else if (name == kDevToolsIssuesPanelOpenedFromHistogram)
-    UMA_HISTOGRAM_EXACT_LINEAR(name, sample, boundary_value);
+    base::UmaHistogramExactLinear(name, sample, boundary_value);
   else if (name == kDevToolsKeybindSetSettingChanged)
-    UMA_HISTOGRAM_EXACT_LINEAR(name, sample, boundary_value);
+    base::UmaHistogramExactLinear(name, sample, boundary_value);
+  else if (name == kDevToolsDualScreenDeviceEmulatedHistogram)
+    base::UmaHistogramExactLinear(name, sample, boundary_value);
   else
     frontend_host_->BadMessageRecieved();
 }
diff --git a/chrome/browser/downgrade/snapshot_file_collector.cc b/chrome/browser/downgrade/snapshot_file_collector.cc
index 974a1a8..1a8b969 100644
--- a/chrome/browser/downgrade/snapshot_file_collector.cc
+++ b/chrome/browser/downgrade/snapshot_file_collector.cc
@@ -132,7 +132,7 @@
           SnapshotItemId::kWebData),
       SnapshotItemDetails(
           base::FilePath(autofill::kStrikeDatabaseFileName),
-          SnapshotItemDetails::ItemType::kFile,
+          SnapshotItemDetails::ItemType::kDirectory,
           ChromeBrowsingDataRemoverDelegate::DATA_TYPE_PASSWORDS |
               ChromeBrowsingDataRemoverDelegate::DATA_TYPE_FORM_DATA,
           SnapshotItemId::kStrikeDatabase),
diff --git a/chrome/browser/download/android/download_dialog_bridge.cc b/chrome/browser/download/android/download_dialog_bridge.cc
new file mode 100644
index 0000000..04c03d8
--- /dev/null
+++ b/chrome/browser/download/android/download_dialog_bridge.cc
@@ -0,0 +1,136 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/download/android/download_dialog_bridge.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/metrics/histogram_macros.h"
+#include "chrome/browser/download/android/download_controller.h"
+#include "chrome/browser/download/android/jni_headers/DownloadDialogBridge_jni.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "ui/android/window_android.h"
+
+// -----------------------------------------------------------------------------
+// DownloadDialogResult
+DownloadDialogResult::DownloadDialogResult() = default;
+
+DownloadDialogResult::DownloadDialogResult(const DownloadDialogResult&) =
+    default;
+
+DownloadDialogResult::~DownloadDialogResult() = default;
+
+// -----------------------------------------------------------------------------
+// DownloadDialogBridge.
+DownloadDialogBridge::DownloadDialogBridge() : is_dialog_showing_(false) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  java_obj_.Reset(env, Java_DownloadDialogBridge_create(
+                           env, reinterpret_cast<intptr_t>(this))
+                           .obj());
+  DCHECK(!java_obj_.is_null());
+}
+
+DownloadDialogBridge::~DownloadDialogBridge() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_DownloadDialogBridge_destroy(env, java_obj_);
+}
+
+void DownloadDialogBridge::ShowDialog(gfx::NativeWindow native_window,
+                                      int64_t total_bytes,
+                                      DownloadLocationDialogType dialog_type,
+                                      const base::FilePath& suggested_path,
+                                      DialogCallback dialog_callback) {
+  if (!native_window)
+    return;
+
+  UMA_HISTOGRAM_ENUMERATION("MobileDownload.Location.Dialog.Type", dialog_type);
+
+  dialog_callback_ = std::move(dialog_callback);
+
+  // This shouldn't happen, but if it does, cancel download.
+  if (dialog_type == DownloadLocationDialogType::NO_DIALOG) {
+    NOTREACHED();
+    DownloadDialogResult dialog_result;
+    dialog_result.location_result = DownloadLocationDialogResult::USER_CANCELED;
+    CompleteSelection(std::move(dialog_result));
+    return;
+  }
+
+  // If dialog is showing, run the callback to continue without confirmation.
+  if (is_dialog_showing_) {
+    DownloadDialogResult dialog_result;
+    dialog_result.location_result =
+        DownloadLocationDialogResult::DUPLICATE_DIALOG;
+    dialog_result.file_path = suggested_path;
+    CompleteSelection(std::move(dialog_result));
+    return;
+  }
+
+  is_dialog_showing_ = true;
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_DownloadDialogBridge_showDialog(
+      env, java_obj_, native_window->GetJavaObject(),
+      static_cast<long>(total_bytes), static_cast<int>(dialog_type),
+      base::android::ConvertUTF8ToJavaString(env,
+                                             suggested_path.AsUTF8Unsafe()));
+}
+
+void DownloadDialogBridge::OnComplete(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj,
+    const base::android::JavaParamRef<jstring>& returned_path) {
+  DownloadDialogResult dialog_result;
+  dialog_result.location_result = DownloadLocationDialogResult::USER_CONFIRMED;
+  dialog_result.file_path = base::FilePath(
+      base::android::ConvertJavaStringToUTF8(env, returned_path));
+
+  CompleteSelection(std::move(dialog_result));
+  is_dialog_showing_ = false;
+}
+
+void DownloadDialogBridge::OnCanceled(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj) {
+  if (dialog_callback_) {
+    DownloadDialogResult dialog_result;
+    dialog_result.location_result = DownloadLocationDialogResult::USER_CANCELED;
+    CompleteSelection(std::move(dialog_result));
+  }
+
+  is_dialog_showing_ = false;
+}
+
+void DownloadDialogBridge::CompleteSelection(DownloadDialogResult result) {
+  if (!dialog_callback_)
+    return;
+
+  UMA_HISTOGRAM_ENUMERATION("MobileDownload.Location.Dialog.Result",
+                            result.location_result);
+  std::move(dialog_callback_).Run(std::move(result));
+}
+
+// static
+base::android::ScopedJavaLocalRef<jstring>
+JNI_DownloadDialogBridge_GetDownloadDefaultDirectory(JNIEnv* env) {
+  PrefService* pref_service =
+      ProfileManager::GetActiveUserProfile()->GetOriginalProfile()->GetPrefs();
+
+  return base::android::ConvertUTF8ToJavaString(
+      env, pref_service->GetString(prefs::kDownloadDefaultDirectory));
+}
+
+// static
+void JNI_DownloadDialogBridge_SetDownloadAndSaveFileDefaultDirectory(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jstring>& directory) {
+  PrefService* pref_service =
+      ProfileManager::GetActiveUserProfile()->GetOriginalProfile()->GetPrefs();
+
+  base::FilePath path(base::android::ConvertJavaStringToUTF8(env, directory));
+  pref_service->SetFilePath(prefs::kDownloadDefaultDirectory, path);
+  pref_service->SetFilePath(prefs::kSaveFileDefaultDirectory, path);
+}
diff --git a/chrome/browser/download/android/download_dialog_bridge.h b/chrome/browser/download/android/download_dialog_bridge.h
index 4432eb4..8018e77 100644
--- a/chrome/browser/download/android/download_dialog_bridge.h
+++ b/chrome/browser/download/android/download_dialog_bridge.h
@@ -7,36 +7,60 @@
 
 #include "base/android/jni_android.h"
 #include "base/android/scoped_java_ref.h"
-#include "chrome/browser/download/download_location_dialog_result.h"
-#include "chrome/browser/download/download_location_dialog_type.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/optional.h"
+#include "chrome/browser/download/download_dialog_types.h"
+#include "components/download/public/common/download_schedule.h"
 #include "ui/gfx/native_widget_types.h"
 
-namespace base {
-class FilePath;
-}  // namespace base
+// Contains all the user selection from download dialogs.
+struct DownloadDialogResult {
+  DownloadDialogResult();
+  DownloadDialogResult(const DownloadDialogResult&);
+  ~DownloadDialogResult();
 
+  // Results from download later dialog.
+  base::Optional<download::DownloadSchedule> download_schedule;
+
+  // Results from download location dialog.
+  DownloadLocationDialogResult location_result =
+      DownloadLocationDialogResult::USER_CONFIRMED;
+  base::FilePath file_path;
+};
+
+// Used to show a dialog for the user to select download details, such as file
+// location, file name. and download start time.
 class DownloadDialogBridge {
  public:
-  using LocationCallback = base::OnceCallback<void(DownloadLocationDialogResult,
-                                                   const base::FilePath&)>;
+  using DialogCallback = base::OnceCallback<void(DownloadDialogResult)>;
 
-  virtual ~DownloadDialogBridge() = default;
+  DownloadDialogBridge();
+  DownloadDialogBridge(const DownloadDialogBridge&) = delete;
+  DownloadDialogBridge& operator=(const DownloadDialogBridge&) = delete;
 
-  // Show a download location picker dialog to determine the download path.
-  // The path selected by the user will be returned in |location_callback|.
+  virtual ~DownloadDialogBridge();
+
+  // Shows the download dialog.
   virtual void ShowDialog(gfx::NativeWindow native_window,
                           int64_t total_bytes,
                           DownloadLocationDialogType dialog_type,
                           const base::FilePath& suggested_path,
-                          LocationCallback location_callback) = 0;
+                          DialogCallback dialog_callback);
 
-  virtual void OnComplete(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jstring>& returned_path) = 0;
+  void OnComplete(JNIEnv* env,
+                  const base::android::JavaParamRef<jobject>& obj,
+                  const base::android::JavaParamRef<jstring>& returned_path);
 
-  virtual void OnCanceled(JNIEnv* env,
-                          const base::android::JavaParamRef<jobject>& obj) = 0;
+  void OnCanceled(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+
+ private:
+  // Called when the user finished the selections from download dialog.
+  void CompleteSelection(DownloadDialogResult result);
+
+  bool is_dialog_showing_;
+  base::android::ScopedJavaGlobalRef<jobject> java_obj_;
+  DialogCallback dialog_callback_;
 };
 
 #endif  // CHROME_BROWSER_DOWNLOAD_ANDROID_DOWNLOAD_DIALOG_BRIDGE_H_
diff --git a/chrome/browser/download/android/download_dialog_bridge_impl.cc b/chrome/browser/download/android/download_dialog_bridge_impl.cc
deleted file mode 100644
index ad7aed3..0000000
--- a/chrome/browser/download/android/download_dialog_bridge_impl.cc
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/download/android/download_dialog_bridge_impl.h"
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_string.h"
-#include "base/metrics/histogram_macros.h"
-#include "chrome/browser/download/android/download_controller.h"
-#include "chrome/browser/download/android/jni_headers/DownloadDialogBridge_jni.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/common/pref_names.h"
-#include "components/prefs/pref_service.h"
-#include "ui/android/window_android.h"
-
-DownloadDialogBridgeImpl::DownloadDialogBridgeImpl()
-    : is_dialog_showing_(false) {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  java_obj_.Reset(env, Java_DownloadDialogBridge_create(
-                           env, reinterpret_cast<intptr_t>(this))
-                           .obj());
-  DCHECK(!java_obj_.is_null());
-}
-
-DownloadDialogBridgeImpl::~DownloadDialogBridgeImpl() {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  Java_DownloadDialogBridge_destroy(env, java_obj_);
-}
-
-void DownloadDialogBridgeImpl::ShowDialog(
-    gfx::NativeWindow native_window,
-    int64_t total_bytes,
-    DownloadLocationDialogType dialog_type,
-    const base::FilePath& suggested_path,
-    LocationCallback location_callback) {
-  if (!native_window)
-    return;
-
-  UMA_HISTOGRAM_ENUMERATION("MobileDownload.Location.Dialog.Type", dialog_type);
-
-  location_callback_ = std::move(location_callback);
-
-  // This shouldn't happen, but if it does, cancel download.
-  if (dialog_type == DownloadLocationDialogType::NO_DIALOG) {
-    NOTREACHED();
-    CompleteLocationSelection(DownloadLocationDialogResult::USER_CANCELED,
-                              base::FilePath());
-    return;
-  }
-
-  // If dialog is showing, run the callback to continue without confirmation.
-  if (is_dialog_showing_) {
-    CompleteLocationSelection(DownloadLocationDialogResult::DUPLICATE_DIALOG,
-                              std::move(suggested_path));
-    return;
-  }
-
-  is_dialog_showing_ = true;
-
-  JNIEnv* env = base::android::AttachCurrentThread();
-  Java_DownloadDialogBridge_showDialog(
-      env, java_obj_, native_window->GetJavaObject(),
-      static_cast<long>(total_bytes), static_cast<int>(dialog_type),
-      base::android::ConvertUTF8ToJavaString(env,
-                                             suggested_path.AsUTF8Unsafe()));
-}
-
-void DownloadDialogBridgeImpl::OnComplete(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& obj,
-    const base::android::JavaParamRef<jstring>& returned_path) {
-  base::FilePath path(
-      base::android::ConvertJavaStringToUTF8(env, returned_path));
-
-  CompleteLocationSelection(DownloadLocationDialogResult::USER_CONFIRMED, path);
-
-  is_dialog_showing_ = false;
-}
-
-void DownloadDialogBridgeImpl::OnCanceled(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& obj) {
-  if (location_callback_) {
-    CompleteLocationSelection(DownloadLocationDialogResult::USER_CANCELED,
-                              base::FilePath());
-  }
-
-  is_dialog_showing_ = false;
-}
-
-void DownloadDialogBridgeImpl::CompleteLocationSelection(
-    DownloadLocationDialogResult result,
-    base::FilePath file_path) {
-  if (location_callback_) {
-    UMA_HISTOGRAM_ENUMERATION("MobileDownload.Location.Dialog.Result", result);
-    std::move(location_callback_).Run(result, std::move(file_path));
-  }
-}
-
-static base::android::ScopedJavaLocalRef<jstring>
-JNI_DownloadDialogBridge_GetDownloadDefaultDirectory(JNIEnv* env) {
-  PrefService* pref_service =
-      ProfileManager::GetActiveUserProfile()->GetOriginalProfile()->GetPrefs();
-
-  return base::android::ConvertUTF8ToJavaString(
-      env, pref_service->GetString(prefs::kDownloadDefaultDirectory));
-}
-
-static void JNI_DownloadDialogBridge_SetDownloadAndSaveFileDefaultDirectory(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jstring>& directory) {
-  PrefService* pref_service =
-      ProfileManager::GetActiveUserProfile()->GetOriginalProfile()->GetPrefs();
-
-  base::FilePath path(base::android::ConvertJavaStringToUTF8(env, directory));
-  pref_service->SetFilePath(prefs::kDownloadDefaultDirectory, path);
-  pref_service->SetFilePath(prefs::kSaveFileDefaultDirectory, path);
-}
diff --git a/chrome/browser/download/android/download_dialog_bridge_impl.h b/chrome/browser/download/android/download_dialog_bridge_impl.h
deleted file mode 100644
index 2d9d433b..0000000
--- a/chrome/browser/download/android/download_dialog_bridge_impl.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_DOWNLOAD_ANDROID_DOWNLOAD_DIALOG_BRIDGE_IMPL_H_
-#define CHROME_BROWSER_DOWNLOAD_ANDROID_DOWNLOAD_DIALOG_BRIDGE_IMPL_H_
-
-#include "base/android/jni_android.h"
-#include "base/android/scoped_java_ref.h"
-#include "base/callback.h"
-#include "chrome/browser/download/android/download_dialog_bridge.h"
-#include "chrome/browser/download/download_location_dialog_type.h"
-#include "ui/gfx/native_widget_types.h"
-
-class DownloadDialogBridgeImpl : public DownloadDialogBridge {
- public:
-  DownloadDialogBridgeImpl();
-  ~DownloadDialogBridgeImpl() override;
-
-  // DownloadDialogBridge implementation.
-  void ShowDialog(gfx::NativeWindow native_window,
-                  int64_t total_bytes,
-                  DownloadLocationDialogType dialog_type,
-                  const base::FilePath& suggested_path,
-                  LocationCallback location_callback) override;
-
-  void OnComplete(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jstring>& returned_path) override;
-
-  void OnCanceled(JNIEnv* env,
-                  const base::android::JavaParamRef<jobject>& obj) override;
-
- private:
-  // Called when the download location is selected by the user.
-  void CompleteLocationSelection(DownloadLocationDialogResult result,
-                                 base::FilePath file_path);
-
-  bool is_dialog_showing_;
-  base::android::ScopedJavaGlobalRef<jobject> java_obj_;
-  LocationCallback location_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(DownloadDialogBridgeImpl);
-};
-
-#endif  // CHROME_BROWSER_DOWNLOAD_ANDROID_DOWNLOAD_DIALOG_BRIDGE_IMPL_H_
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index 5fc300c..b28c711 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -29,10 +29,10 @@
 #include "chrome/browser/download/download_core_service.h"
 #include "chrome/browser/download/download_core_service_factory.h"
 #include "chrome/browser/download/download_crx_util.h"
+#include "chrome/browser/download/download_dialog_types.h"
 #include "chrome/browser/download/download_file_picker.h"
 #include "chrome/browser/download/download_history.h"
 #include "chrome/browser/download/download_item_model.h"
-#include "chrome/browser/download/download_location_dialog_type.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/download/download_request_limiter.h"
 #include "chrome/browser/download/download_stats.h"
@@ -86,7 +86,7 @@
 #include "base/android/path_utils.h"
 #include "chrome/browser/download/android/chrome_duplicate_download_infobar_delegate.h"
 #include "chrome/browser/download/android/download_controller.h"
-#include "chrome/browser/download/android/download_dialog_bridge_impl.h"
+#include "chrome/browser/download/android/download_dialog_bridge.h"
 #include "chrome/browser/download/android/download_manager_service.h"
 #include "chrome/browser/download/android/download_open_source.h"
 #include "chrome/browser/download/android/download_utils.h"
@@ -248,13 +248,13 @@
 }
 
 // Overlays download location dialog result to target determiner.
-void OnDownloadLocationDetermined(
+void OnDownloadDialogClosed(
     const DownloadTargetDeterminerDelegate::ConfirmationCallback& callback,
-    DownloadLocationDialogResult result,
-    const base::FilePath& path) {
-  switch (result) {
+    DownloadDialogResult result) {
+  switch (result.location_result) {
     case DownloadLocationDialogResult::USER_CONFIRMED:
-      callback.Run(DownloadConfirmationResult::CONFIRMED_WITH_DIALOG, path);
+      callback.Run(DownloadConfirmationResult::CONFIRMED_WITH_DIALOG,
+                   result.file_path);
       break;
     case DownloadLocationDialogResult::USER_CANCELED:
       callback.Run(DownloadConfirmationResult::CANCELED, base::FilePath());
@@ -264,7 +264,7 @@
       // Currently we just let other downloads continue, which doesn't make
       // sense.
       callback.Run(DownloadConfirmationResult::CONTINUE_WITHOUT_CONFIRMATION,
-                   path);
+                   result.file_path);
       break;
   }
 }
@@ -319,7 +319,7 @@
       download_prefs_(new DownloadPrefs(profile)),
       is_file_picker_showing_(false) {
 #if defined(OS_ANDROID)
-  download_dialog_bridge_.reset(new DownloadDialogBridgeImpl);
+  download_dialog_bridge_.reset(new DownloadDialogBridge);
 #endif
 }
 
@@ -340,12 +340,12 @@
 }
 
 #if defined(OS_ANDROID)
-void ChromeDownloadManagerDelegate::ChooseDownloadLocation(
+void ChromeDownloadManagerDelegate::ShowDownloadDialog(
     gfx::NativeWindow native_window,
     int64_t total_bytes,
     DownloadLocationDialogType dialog_type,
     const base::FilePath& suggested_path,
-    DownloadDialogBridge::LocationCallback callback) {
+    DownloadDialogBridge::DialogCallback callback) {
   DCHECK(download_dialog_bridge_);
   download_dialog_bridge_->ShowDialog(native_window, total_bytes, dialog_type,
                                       suggested_path, std::move(callback));
@@ -929,9 +929,9 @@
       }
 
       gfx::NativeWindow native_window = web_contents->GetTopLevelNativeWindow();
-      ChooseDownloadLocation(
-          native_window, download->GetTotalBytes(), dialog_type, suggested_path,
-          base::BindOnce(&OnDownloadLocationDetermined, callback));
+      ShowDownloadDialog(native_window, download->GetTotalBytes(), dialog_type,
+                         suggested_path,
+                         base::BindOnce(&OnDownloadDialogClosed, callback));
     }
   } else {
     switch (reason) {
@@ -1046,10 +1046,9 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (result == PathValidationResult::SUCCESS) {
     if (download_prefs_->PromptForDownload()) {
-      ChooseDownloadLocation(
-          native_window, 0 /* total_bytes */,
-          DownloadLocationDialogType::NAME_CONFLICT, target_path,
-          base::BindOnce(&OnDownloadLocationDetermined, callback));
+      ShowDownloadDialog(native_window, 0 /* total_bytes */,
+                         DownloadLocationDialogType::NAME_CONFLICT, target_path,
+                         base::BindOnce(&OnDownloadDialogClosed, callback));
       return;
     }
 
diff --git a/chrome/browser/download/chrome_download_manager_delegate.h b/chrome/browser/download/chrome_download_manager_delegate.h
index d152e66..b5568e5 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.h
+++ b/chrome/browser/download/chrome_download_manager_delegate.h
@@ -64,11 +64,11 @@
   void SetDownloadManager(content::DownloadManager* dm);
 
 #if defined(OS_ANDROID)
-  void ChooseDownloadLocation(gfx::NativeWindow native_window,
-                              int64_t total_bytes,
-                              DownloadLocationDialogType dialog_type,
-                              const base::FilePath& suggested_path,
-                              DownloadDialogBridge::LocationCallback callback);
+  void ShowDownloadDialog(gfx::NativeWindow native_window,
+                          int64_t total_bytes,
+                          DownloadLocationDialogType dialog_type,
+                          const base::FilePath& suggested_path,
+                          DownloadDialogBridge::DialogCallback callback);
 
   void SetDownloadDialogBridgeForTesting(DownloadDialogBridge* bridge);
 #endif
diff --git a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
index 8865e48..4635e27 100644
--- a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
@@ -1688,30 +1688,23 @@
 
 class TestDownloadDialogBridge : public DownloadDialogBridge {
  public:
-  TestDownloadDialogBridge() {}
+  TestDownloadDialogBridge() = default;
 
   // DownloadDialogBridge implementation.
   void ShowDialog(gfx::NativeWindow native_window,
                   int64_t total_bytes,
                   DownloadLocationDialogType dialog_type,
                   const base::FilePath& suggested_path,
-                  DownloadDialogBridge::LocationCallback callback) override {
+                  DownloadDialogBridge::DialogCallback callback) override {
     dialog_shown_count_++;
     dialog_type_ = dialog_type;
     if (callback) {
-      std::move(callback).Run(DownloadLocationDialogResult::USER_CANCELED,
-                              base::FilePath());
+      DownloadDialogResult result;
+      result.location_result = DownloadLocationDialogResult::USER_CANCELED;
+      std::move(callback).Run(std::move(result));
     }
   }
 
-  void OnComplete(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jstring>& returned_path) override {}
-
-  void OnCanceled(JNIEnv* env,
-                  const base::android::JavaParamRef<jobject>& obj) override {}
-
   // Returns the number of times ShowDialog has been called.
   int GetDialogShownCount() { return dialog_shown_count_; }
 
diff --git a/chrome/browser/download/download_location_dialog_type.h b/chrome/browser/download/download_dialog_types.h
similarity index 61%
rename from chrome/browser/download/download_location_dialog_type.h
rename to chrome/browser/download/download_dialog_types.h
index 80b5900..8a73e844 100644
--- a/chrome/browser/download/download_location_dialog_type.h
+++ b/chrome/browser/download/download_dialog_types.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_LOCATION_DIALOG_TYPE_H_
-#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_LOCATION_DIALOG_TYPE_H_
+#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_DIALOG_TYPES_H_
+#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_DIALOG_TYPES_H_
 
 // The type of download location dialog that should by shown by Android.
 // A Java counterpart will be generated for this enum.
@@ -20,4 +20,14 @@
   kMaxValue = NAME_TOO_LONG
 };
 
-#endif  // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_LOCATION_DIALOG_TYPE_H_
+// Result of download location dialog.
+// Recorded in histogram, so do not delete or reuse entries. The values must
+// match DownloadLocationDialogResult in enums.xml.
+enum class DownloadLocationDialogResult {
+  USER_CONFIRMED = 0,    // User confirmed a file path.
+  USER_CANCELED = 1,     // User canceled file path selection.
+  DUPLICATE_DIALOG = 2,  // Dialog is already showing.
+  kMaxValue = DUPLICATE_DIALOG
+};
+
+#endif  // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_DIALOG_TYPES_H_
diff --git a/chrome/browser/download/download_location_dialog_result.h b/chrome/browser/download/download_location_dialog_result.h
deleted file mode 100644
index e6f209cd..0000000
--- a/chrome/browser/download/download_location_dialog_result.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_LOCATION_DIALOG_RESULT_H_
-#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_LOCATION_DIALOG_RESULT_H_
-
-// Result of download location dialog.
-// Recorded in histogram, so do not delete or reuse entries. The values must
-// match DownloadLocationDialogResult in enums.xml.
-enum class DownloadLocationDialogResult {
-  USER_CONFIRMED = 0,    // User confirmed a file path.
-  USER_CANCELED = 1,     // User canceled file path selection.
-  DUPLICATE_DIALOG = 2,  // Dialog is already showing.
-  kMaxValue = DUPLICATE_DIALOG
-};
-
-#endif  // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_LOCATION_DIALOG_RESULT_H_
diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc
index e74ee4f..82b4d8f 100644
--- a/chrome/browser/download/save_page_browsertest.cc
+++ b/chrome/browser/download/save_page_browsertest.cc
@@ -1442,7 +1442,14 @@
 }
 
 // Test for saving a page with a cross-site <object> element.
-IN_PROC_BROWSER_TEST_P(SavePageOriginalVsSavedComparisonTest, CrossSiteObject) {
+// Disabled on Windows due to flakiness. crbug.com/1070597.
+#if defined(OS_WIN)
+#define MAYBE_CrossSiteObject DISABLED_CrossSiteObject
+#else
+#define MAYBE_CrossSiteObject CrossSiteObject
+#endif
+IN_PROC_BROWSER_TEST_P(SavePageOriginalVsSavedComparisonTest,
+                       MAYBE_CrossSiteObject) {
   content::SavePageType save_page_type = GetParam();
 
   std::vector<std::string> expected_substrings = {
diff --git a/chrome/browser/engagement/important_sites_usage_counter_unittest.cc b/chrome/browser/engagement/important_sites_usage_counter_unittest.cc
index bbca56581..2da85b0 100644
--- a/chrome/browser/engagement/important_sites_usage_counter_unittest.cc
+++ b/chrome/browser/engagement/important_sites_usage_counter_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/run_loop.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
@@ -20,6 +21,7 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_utils.h"
+#include "storage/browser/quota/quota_client_type.h"
 #include "storage/browser/quota/quota_manager_proxy.h"
 #include "storage/browser/test/mock_quota_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -53,7 +55,8 @@
   void RegisterClient(const std::vector<storage::MockOriginData>& data) {
     auto* client = new storage::MockQuotaClient(
         quota_manager_->proxy(), data, storage::QuotaClientType::kFileSystem);
-    quota_manager_->proxy()->RegisterClient(client);
+    quota_manager_->proxy()->RegisterClient(
+        client, storage::QuotaClientType::kFileSystem);
     client->TouchAllOriginsAndNotify();
   }
 
diff --git a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc
index e650e3f..343c894 100644
--- a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc
+++ b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h"
 
 #include "base/bind.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/extensions/api/identity/identity_api.h"
 #include "chrome/browser/profiles/profile.h"
@@ -24,6 +25,15 @@
 
 namespace extensions {
 
+namespace {
+
+void RecordResultHistogram(GaiaRemoteConsentFlow::Failure failure) {
+  base::UmaHistogramEnumeration("Signin.Extensions.GaiaRemoteConsentFlowResult",
+                                failure);
+}
+
+}  // namespace
+
 GaiaRemoteConsentFlow::Delegate::~Delegate() = default;
 
 GaiaRemoteConsentFlow::GaiaRemoteConsentFlow(
@@ -61,7 +71,7 @@
   }
 
   if (result != signin::SetAccountsInCookieResult::kSuccess) {
-    delegate_->OnGaiaRemoteConsentFlowFailed(
+    GaiaRemoteConsentFlowFailed(
         GaiaRemoteConsentFlow::Failure::SET_ACCOUNTS_IN_COOKIE_FAILED);
     return;
   }
@@ -100,16 +110,16 @@
   std::string gaia_id;
   if (!gaia::ParseOAuth2MintTokenConsentResult(consent_result,
                                                &consent_approved, &gaia_id)) {
-    delegate_->OnGaiaRemoteConsentFlowFailed(
-        GaiaRemoteConsentFlow::INVALID_CONSENT_RESULT);
+    GaiaRemoteConsentFlowFailed(GaiaRemoteConsentFlow::INVALID_CONSENT_RESULT);
     return;
   }
 
   if (!consent_approved) {
-    delegate_->OnGaiaRemoteConsentFlowFailed(GaiaRemoteConsentFlow::NO_GRANT);
+    GaiaRemoteConsentFlowFailed(GaiaRemoteConsentFlow::NO_GRANT);
     return;
   }
 
+  RecordResultHistogram(GaiaRemoteConsentFlow::NONE);
   delegate_->OnGaiaRemoteConsentFlowApproved(consent_result, gaia_id);
 }
 
@@ -129,7 +139,7 @@
       break;
   }
 
-  delegate_->OnGaiaRemoteConsentFlowFailed(gaia_failure);
+  GaiaRemoteConsentFlowFailed(gaia_failure);
 }
 
 std::unique_ptr<GaiaAuthFetcher>
@@ -196,4 +206,9 @@
                              base::Unretained(this)));
 }
 
+void GaiaRemoteConsentFlow::GaiaRemoteConsentFlowFailed(Failure failure) {
+  RecordResultHistogram(failure);
+  delegate_->OnGaiaRemoteConsentFlowFailed(failure);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h
index 433777b..0fd5cc8 100644
--- a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h
+++ b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h
@@ -25,12 +25,16 @@
       public signin::AccountsCookieMutator::PartitionDelegate,
       public signin::IdentityManager::Observer {
  public:
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
   enum Failure {
-    WINDOW_CLOSED,
-    LOAD_FAILED,
-    SET_ACCOUNTS_IN_COOKIE_FAILED,
-    INVALID_CONSENT_RESULT,
-    NO_GRANT
+    NONE = 0,
+    WINDOW_CLOSED = 1,
+    LOAD_FAILED = 2,
+    SET_ACCOUNTS_IN_COOKIE_FAILED = 3,
+    INVALID_CONSENT_RESULT = 4,
+    NO_GRANT = 5,
+    kMaxValue = NO_GRANT
   };
 
   class Delegate {
@@ -80,6 +84,8 @@
  private:
   void SetAccountsInCookie();
 
+  void GaiaRemoteConsentFlowFailed(Failure failure);
+
   Delegate* delegate_;
   Profile* profile_;
   CoreAccountId account_id_;
diff --git a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc
index fa1a7c1..bf65e81 100644
--- a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc
+++ b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "base/run_loop.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
@@ -17,6 +18,9 @@
 
 namespace extensions {
 
+const char kResultHistogramName[] =
+    "Signin.Extensions.GaiaRemoteConsentFlowResult";
+
 const char kWindowKey[] = "window_key";
 const char kGaiaId[] = "fake_gaia_id";
 const char kConsentResult[] = "CAESCUVOQ1JZUFRFRBoMZmFrZV9nYWlhX2lk";
@@ -98,8 +102,11 @@
                                       window_key));
   }
 
+  base::HistogramTester* histogram_tester() { return &histogram_tester_; }
+
  protected:
   base::test::TaskEnvironment task_env_;
+  base::HistogramTester histogram_tester_;
   testing::StrictMock<MockGaiaRemoteConsentFlowDelegate> delegate_;
 };
 
@@ -108,6 +115,8 @@
   EXPECT_CALL(delegate_,
               OnGaiaRemoteConsentFlowApproved(kConsentResult, kGaiaId));
   flow->OnConsentResultSet(kConsentResult, kWindowKey);
+  histogram_tester()->ExpectUniqueSample(kResultHistogramName,
+                                         GaiaRemoteConsentFlow::NONE, 1);
 }
 
 TEST_F(IdentityGaiaRemoteConsentFlowTest, ConsentResult_WrongWindowIgnored) {
@@ -130,6 +139,8 @@
   EXPECT_CALL(delegate_,
               OnGaiaRemoteConsentFlowApproved(kConsentResult, kGaiaId));
   flow->OnConsentResultSet(kConsentResult, kWindowKey);
+  histogram_tester()->ExpectUniqueSample(kResultHistogramName,
+                                         GaiaRemoteConsentFlow::NONE, 2);
 }
 
 TEST_F(IdentityGaiaRemoteConsentFlowTest, InvalidConsentResult) {
@@ -139,6 +150,8 @@
               OnGaiaRemoteConsentFlowFailed(
                   GaiaRemoteConsentFlow::Failure::INVALID_CONSENT_RESULT));
   flow->OnConsentResultSet(kInvalidConsentResult, kWindowKey);
+  histogram_tester()->ExpectUniqueSample(
+      kResultHistogramName, GaiaRemoteConsentFlow::INVALID_CONSENT_RESULT, 1);
 }
 
 TEST_F(IdentityGaiaRemoteConsentFlowTest, NoGrant) {
@@ -147,6 +160,8 @@
   EXPECT_CALL(delegate_, OnGaiaRemoteConsentFlowFailed(
                              GaiaRemoteConsentFlow::Failure::NO_GRANT));
   flow->OnConsentResultSet(kNoGrantConsentResult, kWindowKey);
+  histogram_tester()->ExpectUniqueSample(kResultHistogramName,
+                                         GaiaRemoteConsentFlow::NO_GRANT, 1);
 }
 
 TEST_F(IdentityGaiaRemoteConsentFlowTest, SetAccountsFailure) {
@@ -157,6 +172,9 @@
           GaiaRemoteConsentFlow::Failure::SET_ACCOUNTS_IN_COOKIE_FAILED));
   flow->OnSetAccountsComplete(
       signin::SetAccountsInCookieResult::kPersistentError);
+  histogram_tester()->ExpectUniqueSample(
+      kResultHistogramName,
+      GaiaRemoteConsentFlow::SET_ACCOUNTS_IN_COOKIE_FAILED, 1);
 }
 
 TEST_F(IdentityGaiaRemoteConsentFlowTest, WebAuthFlowFailure_WindowClosed) {
@@ -164,6 +182,8 @@
   EXPECT_CALL(delegate_, OnGaiaRemoteConsentFlowFailed(
                              GaiaRemoteConsentFlow::Failure::WINDOW_CLOSED));
   flow->OnAuthFlowFailure(WebAuthFlow::Failure::WINDOW_CLOSED);
+  histogram_tester()->ExpectUniqueSample(
+      kResultHistogramName, GaiaRemoteConsentFlow::WINDOW_CLOSED, 1);
 }
 
 TEST_F(IdentityGaiaRemoteConsentFlowTest, WebAuthFlowFailure_LoadFailed) {
@@ -171,6 +191,8 @@
   EXPECT_CALL(delegate_, OnGaiaRemoteConsentFlowFailed(
                              GaiaRemoteConsentFlow::Failure::LOAD_FAILED));
   flow->OnAuthFlowFailure(WebAuthFlow::Failure::LOAD_FAILED);
+  histogram_tester()->ExpectUniqueSample(kResultHistogramName,
+                                         GaiaRemoteConsentFlow::LOAD_FAILED, 1);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc
index 4f274ba..6398331 100644
--- a/chrome/browser/extensions/api/identity/identity_apitest.cc
+++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -657,9 +657,9 @@
 }
 
 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,
-                       PrimaryAccountHasNoRefreshToken) {
+                       PrimaryAccountHasInvalidRefreshToken) {
   CoreAccountId primary_account_id = SignIn("primary@example.com");
-  identity_test_env()->RemoveRefreshTokenForAccount(primary_account_id);
+  identity_test_env()->SetInvalidRefreshTokenForPrimaryAccount();
   EXPECT_TRUE(ExpectGetAccounts({}));
 }
 
@@ -2679,19 +2679,19 @@
 #endif  // !defined(OS_CHROMEOS)
 
 // Test that an event is fired when the primary account has a refresh token
-// revoked.
+// invalidated.
 IN_PROC_BROWSER_TEST_F(OnSignInChangedEventTest,
-                       FireOnPrimaryAccountRefreshTokenRevoked) {
+                       FireOnPrimaryAccountRefreshTokenInvalidated) {
   api::identity::AccountInfo account_info;
   account_info.id = "gaia_id_for_primary_example.com";
   AddExpectedEvent(api::identity::OnSignInChanged::Create(account_info, true));
 
   CoreAccountId primary_account_id = SignIn("primary@example.com");
 
-  AddExpectedEvent(api::identity::OnSignInChanged::Create(account_info, false));
+  AddExpectedEvent(api::identity::OnSignInChanged::Create(account_info, true));
 
   // Revoke the refresh token and verify that the callback fires.
-  identity_test_env()->RemoveRefreshTokenForAccount(primary_account_id);
+  identity_test_env()->SetInvalidRefreshTokenForPrimaryAccount();
 
   EXPECT_FALSE(HasExpectedEvent());
 }
@@ -2706,14 +2706,14 @@
 
   CoreAccountId primary_account_id = SignIn("primary@example.com");
 
-  AddExpectedEvent(api::identity::OnSignInChanged::Create(account_info, false));
-  identity_test_env()->RemoveRefreshTokenForAccount(primary_account_id);
+  AddExpectedEvent(api::identity::OnSignInChanged::Create(account_info, true));
+  identity_test_env()->SetInvalidRefreshTokenForPrimaryAccount();
 
   account_info.id = "gaia_id_for_primary_example.com";
   AddExpectedEvent(api::identity::OnSignInChanged::Create(account_info, true));
 
   // Make the primary account available again and check that the callback fires.
-  identity_test_env()->MakeAccountAvailable("primary@example.com");
+  identity_test_env()->SetRefreshTokenForPrimaryAccount();
   EXPECT_FALSE(HasExpectedEvent());
 }
 
diff --git a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
index 2658144..6b6c09d 100644
--- a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
+++ b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/location.h"
+#include "base/notreached.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "build/build_config.h"
@@ -730,6 +731,10 @@
     case GaiaRemoteConsentFlow::NO_GRANT:
       error = identity_constants::kNoGrant;
       break;
+
+    case GaiaRemoteConsentFlow::NONE:
+      NOTREACHED();
+      break;
   }
 
   CompleteFunctionWithError(error);
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api.cc b/chrome/browser/extensions/api/input_ime/input_ime_api.cc
index e9747f3b..37ea54f9 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api.cc
@@ -17,7 +17,7 @@
 namespace SetComposition = extensions::api::input_ime::SetComposition;
 namespace CommitText = extensions::api::input_ime::CommitText;
 namespace SendKeyEvents = extensions::api::input_ime::SendKeyEvents;
-using input_method::InputMethodEngineBase;
+using chromeos::InputMethodEngineBase;
 
 namespace {
 const char kErrorRouterNotAvailable[] = "The router is not available.";
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api.h b/chrome/browser/extensions/api/input_ime/input_ime_api.h
index fdbfe0d3..934a51ef 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api.h
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api.h
@@ -38,19 +38,21 @@
 namespace ui {
 class IMEEngineHandlerInterface;
 
-class ImeObserver : public input_method::InputMethodEngineBase::Observer {
+using chromeos::InputMethodEngineBase;
+
+class ImeObserver : public InputMethodEngineBase::Observer {
  public:
   ImeObserver(const std::string& extension_id, Profile* profile);
 
   ~ImeObserver() override = default;
 
-  // input_method::InputMethodEngineBase::Observer overrides.
+  // InputMethodEngineBase::Observer overrides.
   void OnActivate(const std::string& component_id) override;
   void OnFocus(const IMEEngineHandlerInterface::InputContext& context) override;
   void OnBlur(int context_id) override;
   void OnKeyEvent(
       const std::string& component_id,
-      const input_method::InputMethodEngineBase::KeyboardEvent& event,
+      const InputMethodEngineBase::KeyboardEvent& event,
       IMEEngineHandlerInterface::KeyEventDoneCallback key_data) override;
   void OnReset(const std::string& component_id) override;
   void OnDeactivated(const std::string& component_id) override;
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
index c891289..221e282 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
@@ -57,9 +57,9 @@
     extensions::api::input_method_private::SetSelectionRange;
 namespace FinishComposingText =
     extensions::api::input_method_private::FinishComposingText;
-using ui::IMEEngineHandlerInterface;
-using input_method::InputMethodEngineBase;
 using chromeos::InputMethodEngine;
+using chromeos::InputMethodEngineBase;
+using ui::IMEEngineHandlerInterface;
 
 namespace {
 const char kErrorEngineNotAvailable[] = "The engine is not available.";
@@ -141,7 +141,7 @@
 
   ~ImeObserverChromeOS() override = default;
 
-  // input_method::InputMethodEngineBase::Observer overrides.
+  // chromeos::InputMethodEngineBase::Observer overrides.
   void OnInputContextUpdate(
       const IMEEngineHandlerInterface::InputContext& context) override {
     if (extension_id_.empty() ||
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h
index c9c86e1..aa03b45 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h
@@ -188,7 +188,7 @@
   void UnregisterAllImes(const std::string& extension_id);
 
   chromeos::InputMethodEngine* GetEngine(const std::string& extension_id);
-  input_method::InputMethodEngineBase* GetEngineIfActive(
+  chromeos::InputMethodEngineBase* GetEngineIfActive(
       const std::string& extension_id,
       std::string* error) override;
 
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_event_router_base.h b/chrome/browser/extensions/api/input_ime/input_ime_event_router_base.h
index 5bdc562..6d3edec 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_event_router_base.h
+++ b/chrome/browser/extensions/api/input_ime/input_ime_event_router_base.h
@@ -22,7 +22,7 @@
   virtual ~InputImeEventRouterBase();
 
   // Gets the input method engine if the extension is active.
-  virtual input_method::InputMethodEngineBase* GetEngineIfActive(
+  virtual chromeos::InputMethodEngineBase* GetEngineIfActive(
       const std::string& extension_id,
       std::string* error) = 0;
 
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
index 862650e..03fb67c 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
@@ -697,12 +697,13 @@
   // The web store install histograms are a subset of the install histograms.
   // We need to record both histograms here since CrxInstaller::InstallUIAbort
   // is never called for web store install cancellations.
-  std::string histogram_name = user_initiated ? "WebStoreInstallCancel"
-                                              : "WebStoreInstallAbort";
-  ExtensionService::RecordPermissionMessagesHistogram(dummy_extension_.get(),
-                                                      histogram_name.c_str());
+  if (user_initiated) {
+    ExtensionService::RecordPermissionMessagesHistogram(
+        dummy_extension_.get(), "WebStoreInstallCancel");
+  }
 
-  histogram_name = user_initiated ? "InstallCancel" : "InstallAbort";
+  std::string histogram_name =
+      user_initiated ? "InstallCancel" : "InstallAbort";
   ExtensionService::RecordPermissionMessagesHistogram(dummy_extension_.get(),
                                                       histogram_name.c_str());
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index a0e18e81..d203863 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -919,6 +919,11 @@
     "expiry_milestone": 88
   },
   {
+    "name": "disable-progress-bar-animation",
+    "owners": [ "eugenebut", "djean" ],
+    "expiry_milestone": 88
+  },
+  {
     "name": "disable-threaded-scrolling",
     "owners": [ "bokan", "input-dev" ],
     // This flag is a useful debugging control when investigating scrolling
@@ -3796,6 +3801,12 @@
     "expiry_milestone": 88
   },
   {
+    "name": "safety-check-chrome-cleaner-child",
+    "owners": ["rainhard", "msramek",
+      "chrome-friendly-settings@google.com"],
+    "expiry_milestone": 88
+  },
+  {
     "name": "safety-check-ios",
     "owners": [ "andzaytsev", "harrisonsean", "msramek",
       "chrome-friendly-settings@google.com"],
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 6600e44..86a8146 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3056,6 +3056,11 @@
 const char kRunVideoCaptureServiceInBrowserProcessDescription[] =
     "Run the video capture service in the browser process.";
 
+const char kSafetyCheckChromeCleanerChildName[] =
+    "Chrome Cleanup Tool in safety check";
+const char kSafetyCheckChromeCleanerChildDescription[] =
+    "Enables the Chrome Cleanup Tool child in safety check.";
+
 const char kUseAngleName[] = "Choose ANGLE graphics backend";
 const char kUseAngleDescription[] =
     "Choose the graphics backend for ANGLE. D3D11 is used on most Windows "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 740b06bc..81e6d1fa 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1765,6 +1765,9 @@
 extern const char kRunVideoCaptureServiceInBrowserProcessName[];
 extern const char kRunVideoCaptureServiceInBrowserProcessDescription[];
 
+extern const char kSafetyCheckChromeCleanerChildName[];
+extern const char kSafetyCheckChromeCleanerChildDescription[];
+
 extern const char kUseAngleName[];
 extern const char kUseAngleDescription[];
 
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 1ba2b4c8..dadb4fe3 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -330,8 +330,6 @@
     public static final String OMNIBOX_ASSISTANT_VOICE_SEARCH = "OmniboxAssistantVoiceSearch";
     public static final String OMNIBOX_COMPACT_SUGGESTIONS = "OmniboxCompactSuggestions";
     public static final String OMNIBOX_DEFERRED_KEYBOARD_POPUP = "OmniboxDeferredKeyboardPopup";
-    public static final String OMNIBOX_ENABLE_CLIPBOARD_PROVIDER_IMAGE_SUGGESTIONS =
-            "OmniboxEnableClipboardProviderImageSuggestions";
     public static final String OMNIBOX_HIDE_SCHEME_IN_STEADY_STATE =
             "OmniboxUIExperimentHideSteadyStateUrlScheme";
     public static final String OMNIBOX_HIDE_TRIVIAL_SUBDOMAINS_IN_STEADY_STATE =
diff --git a/chrome/browser/infobars/infobar_service.cc b/chrome/browser/infobars/infobar_service.cc
index ad11642..40f5165 100644
--- a/chrome/browser/infobars/infobar_service.cc
+++ b/chrome/browser/infobars/infobar_service.cc
@@ -4,89 +4,15 @@
 
 #include "chrome/browser/infobars/infobar_service.h"
 
-#include "base/command_line.h"
-#include "components/infobars/core/infobar.h"
-#include "content/public/browser/navigation_details.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/content_switches.h"
-#include "ui/base/page_transition_types.h"
-
-// static
-infobars::InfoBarDelegate::NavigationDetails
-    InfoBarService::NavigationDetailsFromLoadCommittedDetails(
-        const content::LoadCommittedDetails& details) {
-  infobars::InfoBarDelegate::NavigationDetails navigation_details;
-  navigation_details.entry_id = details.entry->GetUniqueID();
-  navigation_details.is_navigation_to_different_page =
-      details.is_navigation_to_different_page();
-  navigation_details.did_replace_entry = details.did_replace_entry;
-  const ui::PageTransition transition = details.entry->GetTransitionType();
-  navigation_details.is_reload =
-      ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD);
-  navigation_details.is_redirect = ui::PageTransitionIsRedirect(transition);
-  return navigation_details;
-}
-
-// static
-content::WebContents* InfoBarService::WebContentsFromInfoBar(
-    infobars::InfoBar* infobar) {
-  if (!infobar || !infobar->owner())
-    return NULL;
-  InfoBarService* infobar_service =
-      static_cast<InfoBarService*>(infobar->owner());
-  return infobar_service->web_contents();
-}
-
 InfoBarService::InfoBarService(content::WebContents* web_contents)
-    : content::WebContentsObserver(web_contents),
-      ignore_next_reload_(false) {
-  DCHECK(web_contents);
-  // Infobar animations cause viewport resizes. Disable them for automated
-  // tests, since they could lead to flakiness.
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableAutomation))
-    set_animations_enabled(false);
-}
+    : infobars::ContentInfoBarManager(web_contents) {}
 
 InfoBarService::~InfoBarService() {
-  ShutDown();
-}
-
-int InfoBarService::GetActiveEntryID() {
-  content::NavigationEntry* active_entry =
-      web_contents()->GetController().GetActiveEntry();
-  return active_entry ? active_entry->GetUniqueID() : 0;
 }
 
 // InfoBarService::CreateConfirmInfoBar() is implemented in platform-specific
 // files.
 
-void InfoBarService::RenderProcessGone(base::TerminationStatus status) {
-  RemoveAllInfoBars(true);
-}
-
-void InfoBarService::DidStartNavigation(
-    content::NavigationHandle* navigation_handle) {
-  if (!navigation_handle->IsInMainFrame() ||
-      navigation_handle->IsSameDocument()) {
-    return;
-  }
-
-  ignore_next_reload_ = false;
-}
-
-void InfoBarService::NavigationEntryCommitted(
-    const content::LoadCommittedDetails& load_details) {
-  const bool ignore = ignore_next_reload_ &&
-      ui::PageTransitionCoreTypeIs(load_details.entry->GetTransitionType(),
-                                   ui::PAGE_TRANSITION_RELOAD);
-  ignore_next_reload_ = false;
-  if (!ignore)
-    OnNavigation(NavigationDetailsFromLoadCommittedDetails(load_details));
-}
-
 void InfoBarService::WebContentsDestroyed() {
   // The WebContents is going away; be aggressively paranoid and delete
   // ourselves lest other parts of the system attempt to add infobars or use
@@ -96,17 +22,4 @@
   // returning from this function is the only safe thing to do.
 }
 
-void InfoBarService::OpenURL(const GURL& url,
-                             WindowOpenDisposition disposition) {
-  // A normal user click on an infobar URL will result in a CURRENT_TAB
-  // disposition; turn that into a NEW_FOREGROUND_TAB so that we don't end up
-  // smashing the page the user is looking at.
-  web_contents()->OpenURL(
-      content::OpenURLParams(url, content::Referrer(),
-                             (disposition == WindowOpenDisposition::CURRENT_TAB)
-                                 ? WindowOpenDisposition::NEW_FOREGROUND_TAB
-                                 : disposition,
-                             ui::PAGE_TRANSITION_LINK, false));
-}
-
 WEB_CONTENTS_USER_DATA_KEY_IMPL(InfoBarService)
diff --git a/chrome/browser/infobars/infobar_service.h b/chrome/browser/infobars/infobar_service.h
index e04c5b3f..e3ca638 100644
--- a/chrome/browser/infobars/infobar_service.h
+++ b/chrome/browser/infobars/infobar_service.h
@@ -10,14 +10,10 @@
 
 #include "base/macros.h"
 #include "build/build_config.h"
-#include "components/infobars/core/infobar_manager.h"
-#include "content/public/browser/reload_type.h"
-#include "content/public/browser/web_contents_observer.h"
+#include "components/infobars/content/content_infobar_manager.h"
 #include "content/public/browser/web_contents_user_data.h"
-#include "ui/base/window_open_disposition.h"
 
 namespace content {
-struct LoadCommittedDetails;
 class WebContents;
 }
 
@@ -25,38 +21,19 @@
 class InfoBar;
 }
 
-// Associates a Tab to a InfoBarManager and manages its lifetime.
-// It manages the infobar notifications and responds to navigation events.
-class InfoBarService : public infobars::InfoBarManager,
-                       public content::WebContentsObserver,
+// //chrome's specialization of ContentInfoBarManager, which implements creation
+// of confirm infobars and ties the lifetime of ContentInfoBarManager instances
+// to that of the WebContents with which they are associated.
+class InfoBarService : public infobars::ContentInfoBarManager,
                        public content::WebContentsUserData<InfoBarService> {
  public:
   ~InfoBarService() override;
 
-  static infobars::InfoBarDelegate::NavigationDetails
-      NavigationDetailsFromLoadCommittedDetails(
-          const content::LoadCommittedDetails& details);
-
-  // This function must only be called on infobars that are owned by an
-  // InfoBarService instance (or not owned at all, in which case this returns
-  // NULL).
-  static content::WebContents* WebContentsFromInfoBar(
-      infobars::InfoBar* infobar);
-
-  // Makes it so the next reload is ignored. That is, if the next commit is a
-  // reload then it is treated as if nothing happened and no infobars are
-  // attempted to be closed.
-  // This is useful for non-user triggered reloads that should not dismiss
-  // infobars. For example, instant may trigger a reload when the google URL
-  // changes.
-  void set_ignore_next_reload() { ignore_next_reload_ = true; }
-
   // InfoBarManager:
   // TODO(sdefresne): Change clients to invoke this on infobars::InfoBarManager
   // and turn the method override private.
   std::unique_ptr<infobars::InfoBar> CreateConfirmInfoBar(
       std::unique_ptr<ConfirmInfoBarDelegate> delegate) override;
-  void OpenURL(const GURL& url, WindowOpenDisposition disposition) override;
 
  protected:
   explicit InfoBarService(content::WebContents* web_contents);
@@ -64,20 +41,9 @@
  private:
   friend class content::WebContentsUserData<InfoBarService>;
 
-  // InfoBarManager:
-  int GetActiveEntryID() override;
-
-  // content::WebContentsObserver:
-  void RenderProcessGone(base::TerminationStatus status) override;
-  void DidStartNavigation(
-      content::NavigationHandle* navigation_handle) override;
-  void NavigationEntryCommitted(
-      const content::LoadCommittedDetails& load_details) override;
+  // infobars::ContentInfoBarManager:
   void WebContentsDestroyed() override;
 
-  // See description in set_ignore_next_reload().
-  bool ignore_next_reload_;
-
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 
   DISALLOW_COPY_AND_ASSIGN(InfoBarService);
diff --git a/chrome/browser/installable/installed_webapp_geolocation_bridge.cc b/chrome/browser/installable/installed_webapp_geolocation_bridge.cc
new file mode 100644
index 0000000..74bc294
--- /dev/null
+++ b/chrome/browser/installable/installed_webapp_geolocation_bridge.cc
@@ -0,0 +1,98 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/installable/installed_webapp_geolocation_bridge.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/metrics/histogram_macros.h"
+#include "chrome/browser/installable/installed_webapp_geolocation_context.h"
+#include "services/device/public/cpp/geolocation/geoposition.h"
+
+InstalledWebappGeolocationBridge::InstalledWebappGeolocationBridge(
+    mojo::PendingReceiver<Geolocation> receiver,
+    const GURL& origin,
+    InstalledWebappGeolocationContext* context)
+    : context_(context),
+      origin_(origin),
+      high_accuracy_(false),
+      has_position_to_report_(false),
+      receiver_(this, std::move(receiver)) {
+  DCHECK(context_);
+  receiver_.set_disconnect_handler(
+      base::BindOnce(&InstalledWebappGeolocationBridge::OnConnectionError,
+                     base::Unretained(this)));
+}
+
+InstalledWebappGeolocationBridge::~InstalledWebappGeolocationBridge() {
+  StopUpdates();
+}
+
+void InstalledWebappGeolocationBridge::StartListeningForUpdates() {
+  // TODO(crbug.com/1069506) Add implementation.
+}
+
+void InstalledWebappGeolocationBridge::StopUpdates() {
+  // TODO(crbug.com/1069506) Add implementation.
+}
+
+void InstalledWebappGeolocationBridge::SetHighAccuracy(bool high_accuracy) {
+  high_accuracy_ = high_accuracy;
+
+  if (device::ValidateGeoposition(position_override_)) {
+    OnLocationUpdate(position_override_);
+    return;
+  }
+
+  StartListeningForUpdates();
+}
+
+void InstalledWebappGeolocationBridge::QueryNextPosition(
+    QueryNextPositionCallback callback) {
+  if (!position_callback_.is_null()) {
+    DVLOG(1) << "Overlapped call to QueryNextPosition!";
+    OnConnectionError();  // Simulate a connection error.
+    return;
+  }
+
+  position_callback_ = std::move(callback);
+
+  if (has_position_to_report_)
+    ReportCurrentPosition();
+}
+
+void InstalledWebappGeolocationBridge::SetOverride(
+    const device::mojom::Geoposition& position) {
+  // TODO(crbug.com/1069506) Add implementation.
+}
+
+void InstalledWebappGeolocationBridge::ClearOverride() {
+  // TODO(crbug.com/1069506) Add implementation.
+}
+
+void InstalledWebappGeolocationBridge::OnConnectionError() {
+  context_->OnConnectionError(this);
+
+  // The above call deleted this instance, so the only safe thing to do is
+  // return.
+}
+
+void InstalledWebappGeolocationBridge::OnLocationUpdate(
+    const device::mojom::Geoposition& position) {
+  DCHECK(context_);
+
+  current_position_ = position;
+  current_position_.valid = device::ValidateGeoposition(position);
+  has_position_to_report_ = true;
+
+  if (!position_callback_.is_null())
+    ReportCurrentPosition();
+}
+
+void InstalledWebappGeolocationBridge::ReportCurrentPosition() {
+  DCHECK(position_callback_);
+  std::move(position_callback_).Run(current_position_.Clone());
+  has_position_to_report_ = false;
+}
diff --git a/chrome/browser/installable/installed_webapp_geolocation_bridge.h b/chrome/browser/installable/installed_webapp_geolocation_bridge.h
new file mode 100644
index 0000000..715eaf0
--- /dev/null
+++ b/chrome/browser/installable/installed_webapp_geolocation_bridge.h
@@ -0,0 +1,71 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_INSTALLABLE_INSTALLED_WEBAPP_GEOLOCATION_BRIDGE_H_
+#define CHROME_BROWSER_INSTALLABLE_INSTALLED_WEBAPP_GEOLOCATION_BRIDGE_H_
+
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "services/device/public/mojom/geolocation.mojom.h"
+#include "services/device/public/mojom/geoposition.mojom.h"
+#include "url/gurl.h"
+
+class InstalledWebappGeolocationContext;
+
+// Implements the Geolocation Mojo interface.
+class InstalledWebappGeolocationBridge : public device::mojom::Geolocation {
+ public:
+  // |context| must outlive this object.
+  InstalledWebappGeolocationBridge(
+      mojo::PendingReceiver<device::mojom::Geolocation> receiver,
+      const GURL& origin,
+      InstalledWebappGeolocationContext* context);
+  InstalledWebappGeolocationBridge(const InstalledWebappGeolocationBridge&) =
+      delete;
+  InstalledWebappGeolocationBridge& operator=(
+      const InstalledWebappGeolocationBridge&) = delete;
+  ~InstalledWebappGeolocationBridge() override;
+
+  // Starts listening for updates.
+  void StartListeningForUpdates();
+  void StopUpdates();
+
+  // Enables and disables geolocation override.
+  void SetOverride(const device::mojom::Geoposition& position);
+  void ClearOverride();
+
+ private:
+  // device::mojom::Geolocation:
+  void SetHighAccuracy(bool high_accuracy) override;
+  void QueryNextPosition(QueryNextPositionCallback callback) override;
+
+  void OnConnectionError();
+
+  void OnLocationUpdate(const device::mojom::Geoposition& position);
+  void ReportCurrentPosition();
+
+  // Owns this object.
+  InstalledWebappGeolocationContext* context_;
+
+  // The callback passed to QueryNextPosition.
+  QueryNextPositionCallback position_callback_;
+
+  // Valid if SetOverride() has been called and ClearOverride() has not
+  // subsequently been called.
+  device::mojom::Geoposition position_override_;
+
+  device::mojom::Geoposition current_position_;
+
+  const GURL origin_;
+
+  // Whether this instance is currently observing location updates with high
+  // accuracy.
+  bool high_accuracy_;
+
+  bool has_position_to_report_;
+
+  // The binding between this object and the other end of the pipe.
+  mojo::Receiver<device::mojom::Geolocation> receiver_;
+};
+
+#endif  // CHROME_BROWSER_INSTALLABLE_INSTALLED_WEBAPP_GEOLOCATION_BRIDGE_H_
diff --git a/chrome/browser/installable/installed_webapp_geolocation_context.cc b/chrome/browser/installable/installed_webapp_geolocation_context.cc
new file mode 100644
index 0000000..2180c09e
--- /dev/null
+++ b/chrome/browser/installable/installed_webapp_geolocation_context.cc
@@ -0,0 +1,51 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/installable/installed_webapp_geolocation_context.h"
+
+#include <utility>
+
+#include "chrome/browser/installable/installed_webapp_geolocation_bridge.h"
+
+InstalledWebappGeolocationContext::InstalledWebappGeolocationContext() =
+    default;
+
+InstalledWebappGeolocationContext::~InstalledWebappGeolocationContext() =
+    default;
+
+void InstalledWebappGeolocationContext::BindGeolocation(
+    mojo::PendingReceiver<device::mojom::Geolocation> receiver,
+    const GURL& requesting_origin) {
+  impls_.push_back(std::make_unique<InstalledWebappGeolocationBridge>(
+      std::move(receiver), requesting_origin, this));
+  if (geoposition_override_)
+    impls_.back()->SetOverride(*geoposition_override_);
+  else
+    impls_.back()->StartListeningForUpdates();
+}
+
+void InstalledWebappGeolocationContext::OnConnectionError(
+    InstalledWebappGeolocationBridge* impl) {
+  for (auto it = impls_.begin(); it != impls_.end(); ++it) {
+    if (impl == it->get()) {
+      impls_.erase(it);
+      return;
+    }
+  }
+}
+
+void InstalledWebappGeolocationContext::SetOverride(
+    device::mojom::GeopositionPtr geoposition) {
+  geoposition_override_ = std::move(geoposition);
+  for (auto& impl : impls_) {
+    impl->SetOverride(*geoposition_override_);
+  }
+}
+
+void InstalledWebappGeolocationContext::ClearOverride() {
+  geoposition_override_.reset();
+  for (auto& impl : impls_) {
+    impl->ClearOverride();
+  }
+}
diff --git a/chrome/browser/installable/installed_webapp_geolocation_context.h b/chrome/browser/installable/installed_webapp_geolocation_context.h
new file mode 100644
index 0000000..56bbdd1
--- /dev/null
+++ b/chrome/browser/installable/installed_webapp_geolocation_context.h
@@ -0,0 +1,48 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_INSTALLABLE_INSTALLED_WEBAPP_GEOLOCATION_CONTEXT_H_
+#define CHROME_BROWSER_INSTALLABLE_INSTALLED_WEBAPP_GEOLOCATION_CONTEXT_H_
+
+#include <memory>
+#include <vector>
+
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "services/device/public/mojom/geolocation.mojom.h"
+#include "services/device/public/mojom/geolocation_context.mojom.h"
+#include "services/device/public/mojom/geoposition.mojom.h"
+
+class InstalledWebappGeolocationBridge;
+
+// Provides information to a set of InstalledWebappGeolocationBridge instances
+// that are associated with a given context. Notably, allows pausing and
+// resuming geolocation on these instances.
+class InstalledWebappGeolocationContext
+    : public device::mojom::GeolocationContext {
+ public:
+  InstalledWebappGeolocationContext();
+  InstalledWebappGeolocationContext(const InstalledWebappGeolocationContext&) =
+      delete;
+  InstalledWebappGeolocationContext& operator=(
+      const InstalledWebappGeolocationContext&) = delete;
+  ~InstalledWebappGeolocationContext() override;
+
+  // mojom::GeolocationContext implementation:
+  void BindGeolocation(
+      mojo::PendingReceiver<device::mojom::Geolocation> receiver,
+      const GURL& requesting_origin) override;
+  void SetOverride(device::mojom::GeopositionPtr geoposition) override;
+  void ClearOverride() override;
+
+  // Called when a InstalledWebappGeolocationBridge has a connection error.
+  // After this call, it is no longer safe to access |impl|.
+  void OnConnectionError(InstalledWebappGeolocationBridge* impl);
+
+ private:
+  std::vector<std::unique_ptr<InstalledWebappGeolocationBridge>> impls_;
+
+  device::mojom::GeopositionPtr geoposition_override_;
+};
+
+#endif  // CHROME_BROWSER_INSTALLABLE_INSTALLED_WEBAPP_GEOLOCATION_CONTEXT_H_
diff --git a/chrome/browser/media/webrtc/media_capture_devices_dispatcher_unittest.cc b/chrome/browser/media/webrtc/media_capture_devices_dispatcher_unittest.cc
index 30d6696e..62ac808 100644
--- a/chrome/browser/media/webrtc/media_capture_devices_dispatcher_unittest.cc
+++ b/chrome/browser/media/webrtc/media_capture_devices_dispatcher_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "build/build_config.h"
 #include "chrome/browser/media/media_access_handler.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -73,7 +74,8 @@
   MediaCaptureDevicesDispatcher* dispatcher_;
 };
 
-TEST_F(MediaCaptureDevicesDispatcherTest, LoopsAllMediaAccessHandlers) {
+TEST_F(MediaCaptureDevicesDispatcherTest,
+       DISABLED_LoopsAllMediaAccessHandlers) {
   media_access_handlers().clear();
 
   // Add two handlers.
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest.cc b/chrome/browser/media/webrtc/webrtc_browsertest.cc
index 0165ea1..c30ac62 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_browsertest.cc
@@ -257,8 +257,9 @@
                                     kKeygenAlgorithmEcdsa, kKeygenAlgorithmRsa);
 }
 
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
-                       RunsAudioVideoWebRTCCallInTwoTabsGetStatsCallback) {
+IN_PROC_BROWSER_TEST_F(
+    MAYBE_WebRtcBrowserTest,
+    DISABLED_RunsAudioVideoWebRTCCallInTwoTabsGetStatsCallback) {
   StartServerAndOpenTabs();
   SetupPeerconnectionWithLocalStream(left_tab_);
   SetupPeerconnectionWithLocalStream(right_tab_);
@@ -286,8 +287,9 @@
   EXPECT_EQ(0u, GetPeerToPeerConnectionsCountChangeFromNetworkService());
 }
 
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
-                       RunsAudioVideoWebRTCCallInTwoTabsGetStatsPromise) {
+IN_PROC_BROWSER_TEST_F(
+    MAYBE_WebRtcBrowserTest,
+    DISABLED_RunsAudioVideoWebRTCCallInTwoTabsGetStatsPromise) {
   StartServerAndOpenTabs();
   SetupPeerconnectionWithLocalStream(left_tab_);
   SetupPeerconnectionWithLocalStream(right_tab_);
diff --git a/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc b/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc
index 061c5dba..7e9bd6a5 100644
--- a/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc
+++ b/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc
@@ -394,8 +394,8 @@
       GetWebContentsGetter(web_contents);
   DownloadControllerBase::Get()->AcquireFileAccessPermission(
       web_contents_getter,
-      base::Bind(&OnOfflinePageAcquireFileAccessPermissionDone,
-                 web_contents_getter, j_tab_ref, origin));
+      base::BindOnce(&OnOfflinePageAcquireFileAccessPermissionDone,
+                     web_contents_getter, j_tab_ref, origin));
 }
 
 static jlong JNI_OfflinePageDownloadBridge_Init(
diff --git a/chrome/browser/offline_pages/android/offline_page_bridge.cc b/chrome/browser/offline_pages/android/offline_page_bridge.cc
index 38c473f..1c52a25 100644
--- a/chrome/browser/offline_pages/android/offline_page_bridge.cc
+++ b/chrome/browser/offline_pages/android/offline_page_bridge.cc
@@ -525,9 +525,9 @@
 
   offline_page_model_->SavePage(
       save_page_params, std::move(archiver), web_contents,
-      base::Bind(&SavePageCallback,
-                 ScopedJavaGlobalRef<jobject>(j_callback_obj),
-                 save_page_params.url));
+      base::BindOnce(&SavePageCallback,
+                     ScopedJavaGlobalRef<jobject>(j_callback_obj),
+                     save_page_params.url));
 }
 
 void OfflinePageBridge::PublishInternalPageByOfflineId(
@@ -541,10 +541,10 @@
 
   offline_page_model->GetPageByOfflineId(
       j_offline_id,
-      base::Bind(&OfflinePageBridge::PublishInternalArchive,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 ScopedJavaGlobalRef<jobject>(j_published_callback),
-                 PublishSource::kPublishByOfflineId));
+      base::BindOnce(&OfflinePageBridge::PublishInternalArchive,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     ScopedJavaGlobalRef<jobject>(j_published_callback),
+                     PublishSource::kPublishByOfflineId));
 }
 
 void OfflinePageBridge::PublishInternalPageByGuid(
@@ -754,11 +754,11 @@
 
   offline_page_model_->GetPageByOfflineId(
       j_offline_id,
-      base::Bind(&OfflinePageBridge::GetPageByOfflineIdDone,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 static_cast<offline_items_collection::LaunchLocation>(
-                     launch_location),
-                 j_callback_ref));
+      base::BindOnce(&OfflinePageBridge::GetPageByOfflineIdDone,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     static_cast<offline_items_collection::LaunchLocation>(
+                         launch_location),
+                     j_callback_ref));
 }
 
 void OfflinePageBridge::GetLoadUrlParamsForOpeningMhtmlFileOrContent(
diff --git a/chrome/browser/offline_pages/background_loader_offliner.cc b/chrome/browser/offline_pages/background_loader_offliner.cc
index 6cec50e..75a7f34 100644
--- a/chrome/browser/offline_pages/background_loader_offliner.cc
+++ b/chrome/browser/offline_pages/background_loader_offliner.cc
@@ -491,15 +491,15 @@
 
   offline_page_model_->SavePage(
       params, std::move(archiver), web_contents,
-      base::Bind(&BackgroundLoaderOffliner::OnPageSaved,
-                 weak_ptr_factory_.GetWeakPtr()));
+      base::BindOnce(&BackgroundLoaderOffliner::OnPageSaved,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void BackgroundLoaderOffliner::RunRenovations() {
   if (page_renovator_) {
     page_renovator_->RunRenovations(
-        base::Bind(&BackgroundLoaderOffliner::RenovationsCompleted,
-                   weak_ptr_factory_.GetWeakPtr()));
+        base::BindOnce(&BackgroundLoaderOffliner::RenovationsCompleted,
+                       weak_ptr_factory_.GetWeakPtr()));
   }
 }
 
@@ -518,8 +518,8 @@
     criteria.offline_ids = std::vector<int64_t>{offline_id};
     offline_page_model_->DeletePagesWithCriteria(
         criteria,
-        base::Bind(&BackgroundLoaderOffliner::DeleteOfflinePageCallback,
-                   weak_ptr_factory_.GetWeakPtr(), request));
+        base::BindOnce(&BackgroundLoaderOffliner::DeleteOfflinePageCallback,
+                       weak_ptr_factory_.GetWeakPtr(), request));
     save_state_ = NONE;
     return;
   }
diff --git a/chrome/browser/offline_pages/offline_page_bookmark_observer.cc b/chrome/browser/offline_pages/offline_page_bookmark_observer.cc
index 38dc5c9..a92480d8 100644
--- a/chrome/browser/offline_pages/offline_page_bookmark_observer.cc
+++ b/chrome/browser/offline_pages/offline_page_bookmark_observer.cc
@@ -34,8 +34,8 @@
   ClientId client_id = ClientId(kBookmarkNamespace, std::to_string(node->id()));
   offline_page_model_->GetOfflineIdsForClientId(
       client_id,
-      base::Bind(&OfflinePageBookmarkObserver::DoDeleteRemovedBookmarkPages,
-                 weak_ptr_factory_.GetWeakPtr()));
+      base::BindOnce(&OfflinePageBookmarkObserver::DoDeleteRemovedBookmarkPages,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void OfflinePageBookmarkObserver::DoDeleteRemovedBookmarkPages(
@@ -44,8 +44,9 @@
   criteria.offline_ids = offline_ids;
   offline_page_model_->DeletePagesWithCriteria(
       criteria,
-      base::Bind(&OfflinePageBookmarkObserver::OnDeleteRemovedBookmarkPagesDone,
-                 weak_ptr_factory_.GetWeakPtr()));
+      base::BindOnce(
+          &OfflinePageBookmarkObserver::OnDeleteRemovedBookmarkPagesDone,
+          weak_ptr_factory_.GetWeakPtr()));
 }
 
 void OfflinePageBookmarkObserver::OnDeleteRemovedBookmarkPagesDone(
diff --git a/chrome/browser/offline_pages/offline_page_request_handler.cc b/chrome/browser/offline_pages/offline_page_request_handler.cc
index 17013da..5cea9d2b 100644
--- a/chrome/browser/offline_pages/offline_page_request_handler.cc
+++ b/chrome/browser/offline_pages/offline_page_request_handler.cc
@@ -378,8 +378,9 @@
         return;
       }
       offline_page_model->GetPageByOfflineId(
-          offline_id, base::Bind(&GetPageByOfflineIdDone, url, offline_header,
-                                 network_state, web_contents_getter, job));
+          offline_id,
+          base::BindOnce(&GetPageByOfflineIdDone, url, offline_header,
+                         network_state, web_contents_getter, job));
       return;
     }
   }
@@ -553,8 +554,9 @@
 
   return stream_->Read(
       dest, dest_size,
-      base::Bind(&OfflinePageRequestHandler::DidReadForServing,
-                 weak_ptr_factory_.GetWeakPtr(), base::WrapRefCounted(dest)));
+      base::BindOnce(&OfflinePageRequestHandler::DidReadForServing,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     base::WrapRefCounted(dest)));
 }
 
 void OfflinePageRequestHandler::OnOfflinePagesAvailable(
@@ -847,10 +849,10 @@
 }
 
 void OfflinePageRequestHandler::ReadForValidation() {
-  int result =
-      stream_->Read(buffer_.get(), kMaxBufferSizeForValidation,
-                    base::Bind(&OfflinePageRequestHandler::DidReadForValidation,
-                               weak_ptr_factory_.GetWeakPtr()));
+  int result = stream_->Read(
+      buffer_.get(), kMaxBufferSizeForValidation,
+      base::BindOnce(&OfflinePageRequestHandler::DidReadForValidation,
+                     weak_ptr_factory_.GetWeakPtr()));
   if (result != net::ERR_IO_PENDING)
     DidReadForValidation(result);
 }
@@ -931,9 +933,9 @@
 
   // Note that we always seek to the beginning of the file because the file may
   // have already been read for validation purpose.
-  int seek_result =
-      stream_->Seek(0, base::Bind(&OfflinePageRequestHandler::DidSeekForServing,
-                                  weak_ptr_factory_.GetWeakPtr()));
+  int seek_result = stream_->Seek(
+      0, base::BindOnce(&OfflinePageRequestHandler::DidSeekForServing,
+                        weak_ptr_factory_.GetWeakPtr()));
   if (seek_result != net::ERR_IO_PENDING)
     DidSeekForServing(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE);
 }
diff --git a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
index f5c233f7..7a644d20 100644
--- a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
+++ b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
@@ -850,8 +850,8 @@
   save_page_params.original_url = original_url;
   OfflinePageModelFactory::GetForBrowserContext(profile())->SavePage(
       save_page_params, std::move(archiver), nullptr,
-      base::Bind(&OfflinePageRequestHandlerTest::OnSavePageDone,
-                 base::Unretained(this)));
+      base::BindOnce(&OfflinePageRequestHandlerTest::OnSavePageDone,
+                     base::Unretained(this)));
   WaitForAsyncOperation();
   return last_offline_id_;
 }
@@ -901,8 +901,8 @@
 OfflinePageItem OfflinePageRequestHandlerTest::GetPage(int64_t offline_id) {
   OfflinePageModelFactory::GetForBrowserContext(profile())->GetPageByOfflineId(
       offline_id,
-      base::Bind(&OfflinePageRequestHandlerTest::OnGetPageByOfflineIdDone,
-                 base::Unretained(this)));
+      base::BindOnce(&OfflinePageRequestHandlerTest::OnGetPageByOfflineIdDone,
+                     base::Unretained(this)));
   RunUntilIdle();
   return page_;
 }
diff --git a/chrome/browser/offline_pages/offline_page_utils.cc b/chrome/browser/offline_pages/offline_page_utils.cc
index c226744..f7aa3097 100644
--- a/chrome/browser/offline_pages/offline_page_utils.cc
+++ b/chrome/browser/offline_pages/offline_page_utils.cc
@@ -102,7 +102,7 @@
         }
       };
 
-  request_coordinator->GetAllRequests(base::Bind(
+  request_coordinator->GetAllRequests(base::BindOnce(
       request_coordinator_continuation, browser_context, url, callback));
 }
 
@@ -309,8 +309,8 @@
   // going to be placed in the public directory.
   AcquireFileAccessPermission(
       web_contents,
-      base::Bind(&AcquireFileAccessPermissionDoneForScheduleDownload,
-                 web_contents, name_space, url, ui_action, request_origin));
+      base::BindOnce(&AcquireFileAccessPermissionDoneForScheduleDownload,
+                     web_contents, name_space, url, ui_action, request_origin));
 }
 
 // static
diff --git a/chrome/browser/offline_pages/prefetch/gcm_token_unittest.cc b/chrome/browser/offline_pages/prefetch/gcm_token_unittest.cc
index ed5ee2469..30b003ab 100644
--- a/chrome/browser/offline_pages/prefetch/gcm_token_unittest.cc
+++ b/chrome/browser/offline_pages/prefetch/gcm_token_unittest.cc
@@ -92,8 +92,8 @@
   result_ = InstanceID::UNKNOWN_ERROR;
 
   GetGCMToken(&profile_, kAppIdForTest,
-              base::Bind(&PrefetchInstanceIDProxyTest::GetTokenCompleted,
-                         base::Unretained(this)));
+              base::BindOnce(&PrefetchInstanceIDProxyTest::GetTokenCompleted,
+                             base::Unretained(this)));
   WaitForAsyncOperation();
   return token_;
 }
diff --git a/chrome/browser/offline_pages/recent_tab_helper.cc b/chrome/browser/offline_pages/recent_tab_helper.cc
index b604c27..772ab98 100644
--- a/chrome/browser/offline_pages/recent_tab_helper.cc
+++ b/chrome/browser/offline_pages/recent_tab_helper.cc
@@ -342,9 +342,9 @@
   // Remove previously captured pages for this tab.
   page_model_->GetOfflineIdsForClientId(
       GetRecentPagesClientId(),
-      base::Bind(&RecentTabHelper::ContinueSnapshotWithIdsToPurge,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 last_n_ongoing_snapshot_info_.get()));
+      base::BindOnce(&RecentTabHelper::ContinueSnapshotWithIdsToPurge,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     last_n_ongoing_snapshot_info_.get()));
 
   IsSavingSamePageEnum saving_same_page_value = IsSavingSamePageEnum::kNewPage;
   if (last_n_latest_saved_snapshot_info_) {
@@ -480,8 +480,8 @@
   page_model_->SavePage(
       save_page_params, delegate_->CreatePageArchiver(web_contents()),
       web_contents(),
-      base::Bind(&RecentTabHelper::SavePageCallback,
-                 weak_ptr_factory_.GetWeakPtr(), snapshot_info));
+      base::BindOnce(&RecentTabHelper::SavePageCallback,
+                     weak_ptr_factory_.GetWeakPtr(), snapshot_info));
 }
 
 void RecentTabHelper::SavePageCallback(SnapshotProgressInfo* snapshot_info,
diff --git a/chrome/browser/offline_pages/recent_tab_helper_unittest.cc b/chrome/browser/offline_pages/recent_tab_helper_unittest.cc
index 28464b4..927807f2 100644
--- a/chrome/browser/offline_pages/recent_tab_helper_unittest.cc
+++ b/chrome/browser/offline_pages/recent_tab_helper_unittest.cc
@@ -262,8 +262,8 @@
 
 const std::vector<OfflinePageItem>& RecentTabHelperTest::GetAllPages() {
   if (all_pages_needs_updating_) {
-    model()->GetAllPages(base::Bind(&RecentTabHelperTest::OnGetAllPagesDone,
-                                    weak_ptr_factory_.GetWeakPtr()));
+    model()->GetAllPages(base::BindOnce(&RecentTabHelperTest::OnGetAllPagesDone,
+                                        weak_ptr_factory_.GetWeakPtr()));
     RunUntilIdle();
     all_pages_needs_updating_ = false;
   }
diff --git a/chrome/browser/page_load_metrics/observers/data_saver_site_breakdown_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/data_saver_site_breakdown_metrics_observer_browsertest.cc
index c200c6a3..40b10771 100644
--- a/chrome/browser/page_load_metrics/observers/data_saver_site_breakdown_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/data_saver_site_breakdown_metrics_observer_browsertest.cc
@@ -361,8 +361,9 @@
                          SaveDataSavingsEstimateBrowserTest,
                          ::testing::ValuesIn(kSaveDataTestCases));
 
+// Flaky on LINUX.  http://crbug.com/1091573
 IN_PROC_BROWSER_TEST_P(SaveDataSavingsEstimateBrowserTest,
-                       DISABLE_ON_WIN_MAC_CHROMEOS(NavigateToSimplePage)) {
+                       DISABLED_NavigateToSimplePage) {
   WaitForDBToInitialize();
 
   for (const auto& test : GetParam().tests) {
diff --git a/chrome/browser/performance_manager/OWNERS b/chrome/browser/performance_manager/OWNERS
index 969f30f..6ef4e6d 100644
--- a/chrome/browser/performance_manager/OWNERS
+++ b/chrome/browser/performance_manager/OWNERS
@@ -1,10 +1 @@
-chrisha@chromium.org
-fdoray@chromium.org
-siggi@chromium.org
-
-# For IPC security review
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
-
-# TEAM: catan-team@chromium.org
-# COMPONENT: Internals>ResourceCoordinator
+file://components/performance_manager/OWNERS
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index dad04b13..235c7909 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -973,6 +973,9 @@
   { key::kPluginVmUserId,
     plugin_vm::prefs::kPluginVmUserId,
     base::Value::Type::STRING },
+  { key::kPluginVmDataCollectionAllowed,
+    plugin_vm::prefs::kPluginVmDataCollectionAllowed,
+    base::Value::Type::BOOLEAN },
   { key::kVoiceInteractionContextEnabled,
     chromeos::assistant::prefs::kAssistantContextEnabled,
     base::Value::Type::BOOLEAN },
diff --git a/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc b/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
index e751319..416cf93 100644
--- a/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
+++ b/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
@@ -495,14 +495,11 @@
     parameters["skip_async_script"] = "true";
     feature_list_.InitWithFeaturesAndParameters(
         {{blink::features::kLightweightNoStatePrefetch, parameters}}, {});
-    fonts_feature_list_.InitAndEnableFeature(
-        blink::features::kLightweightNoStatePrefetch_FetchFonts);
     NoStatePrefetchBrowserTest::SetUp();
   }
 
  private:
   base::test::ScopedFeatureList feature_list_;
-  base::test::ScopedFeatureList fonts_feature_list_;
 };
 
 // Checks that the expected resource types are fetched via NoState Prefetch.
@@ -520,7 +517,7 @@
   WaitForRequestCount(src_server()->GetURL(kPrefetchScript2), 0);
   WaitForRequestCount(src_server()->GetURL(kPrefetchPng), 0);
   WaitForRequestCount(src_server()->GetURL(kPrefetchCss), 1);
-  WaitForRequestCount(src_server()->GetURL(kPrefetchFont), 1);
+  WaitForRequestCount(src_server()->GetURL(kPrefetchFont), 0);
 }
 
 // Test and Test Class for lightweight prefetch under the HTML+CSS+Script
diff --git a/chrome/browser/resources/accessibility/accessibility.html b/chrome/browser/resources/accessibility/accessibility.html
index 1d9b645..6e77f7b 100644
--- a/chrome/browser/resources/accessibility/accessibility.html
+++ b/chrome/browser/resources/accessibility/accessibility.html
@@ -111,23 +111,6 @@
       <div id="label_images_secondary" class="secondary">
         Automatically labels images.
       </div>
-
-      <h2>Command line options:</h2>
-      <p>
-        Accessibility features in Chrome are off by default and enabled
-        automatically on-demand. Changes to these modes only take effect
-        until the next time Chrome is restarted.
-      </p>
-      <p>
-        To force accessibility to be enabled at launch, run Chrome with this
-        flag:
-        <pre>--force-renderer-accessibility</pre>
-      </p>
-      <p>
-        To disable accessibility, run Chrome with this flag:
-        <pre>--disable-renderer-accessibility</pre>
-      </p>
-
     </div>
     <div class="column">
       <h2>Accessibility tree viewing options:</h2>
@@ -181,14 +164,36 @@
       <div id="deny_secondary" class="secondary">
         Exclude these attributes.
       </div>
+    </div>
+  </div>
 
+  <div class="columns">
+    <div class="column">
+      <h2>Command line options:</h2>
+      <p>
+        Accessibility features in Chrome are off by default and enabled
+        automatically on-demand. Changes to these modes only take effect
+        until the next time Chrome is restarted.
+      </p>
+      <p>
+        To force accessibility to be enabled at launch, run Chrome with this
+        flag:
+        <pre>--force-renderer-accessibility</pre>
+      </p>
+      <p>
+        To disable accessibility, run Chrome with this flag:
+        <pre>--disable-renderer-accessibility</pre>
+      </p>
     </div>
   </div>
 
   <h2>Chrome Native UI:</h2>
   <div id="browsers" class="list">
-    Set a delay, in milliseconds, before getting the native accessibility tree:
-    <input type="number" value="0" id="native_ui_delay"> ms
+    <label for="native-ui-delay">
+      Set a delay, in milliseconds, before getting the native accessibility
+      tree:
+    </label>
+    <input id="native-ui-delay" type="number" value="0"> ms
   </div>
 
   <h2>Pages:</h2>
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html
index 42eadd08..b7b3f4c 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html
@@ -44,22 +44,22 @@
             </div>
             <div id="voice-match-entries">
               <voice-match-entry id="voice-entry-0">
-                <div class="entry-content">
+                <div slot="entry-content">
                   [[i18nDynamic(locale, 'assistantVoiceMatchInstruction0')]]
                 </div>
               </voice-match-entry>
               <voice-match-entry id="voice-entry-1">
-                <div class="entry-content">
+                <div slot="entry-content">
                   [[i18nDynamic(locale, 'assistantVoiceMatchInstruction1')]]
                 </div>
               </voice-match-entry>
               <voice-match-entry id="voice-entry-2">
-                <div class="entry-content">
+                <div slot="entry-content">
                   [[i18nDynamic(locale, 'assistantVoiceMatchInstruction2')]]
                 </div>
               </voice-match-entry>
               <voice-match-entry id="voice-entry-3">
-                <div class="entry-content">
+                <div slot="entry-content">
                   [[i18nDynamic(locale, 'assistantVoiceMatchInstruction3')]]
                 </div>
               </voice-match-entry>
diff --git a/chrome/browser/resources/chromeos/assistant_optin/voice_match_entry.html b/chrome/browser/resources/chromeos/assistant_optin/voice_match_entry.html
index 2a9415d..bfd8e1b 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/voice_match_entry.html
+++ b/chrome/browser/resources/chromeos/assistant_optin/voice_match_entry.html
@@ -20,7 +20,7 @@
       </div>
       <div id="entry-text" class="content">
         <div id="active-text" active$="[[active]]">
-          <content select=".entry-content"></content>
+          <slot name="entry-content"></slot>
         </div>
         <div id="completed-text" completed$="[[completed]]">
           [[i18nDynamic(locale, 'assistantVoiceMatchComplete')]]
diff --git a/chrome/browser/resources/chromeos/camera/src/css/main.css b/chrome/browser/resources/chromeos/camera/src/css/main.css
index d45fd0ae..cabf6c7 100644
--- a/chrome/browser/resources/chromeos/camera/src/css/main.css
+++ b/chrome/browser/resources/chromeos/camera/src/css/main.css
@@ -40,14 +40,16 @@
 
 body.tab-navigation button:focus::after,
 body.tab-navigation input:focus::after {
+  --focus-ring-size: 3px;
+
   border: 2px solid rgba(37, 129, 223, 0.7);
   border-radius: 4px;
-  bottom: -3px;
+  bottom: calc(0px - var(--focus-ring-size));
   content: '';
-  left: -3px;
+  left: calc(0px - var(--focus-ring-size));
   position: absolute;
-  right: -3px;
-  top: -3px;
+  right: calc(0px - var(--focus-ring-size));
+  top: calc(0px - var(--focus-ring-size));
 }
 
 .cancel-animate {
@@ -159,7 +161,7 @@
 }
 
 #shutters-group {
-  bottom: calc((var(--modes-bottom) + var(--modes-height)) + 16px);
+  bottom: calc((var(--modes-bottom) + var(--modes-height)) + 22px);
 }
 
 body.review-result #shutters-group {
@@ -299,11 +301,15 @@
 
 button.shutter {
   display: none;
-  height: 72px;
-  width: 72px;
+  height: 60px;
+  width: 60px;
   z-index: 1;  /* On top of transforming switch-mode buttons. */
 }
 
+body.tab-navigation button.shutter:focus::after {
+  --focus-ring-size: 9px;
+}
+
 body.video #recordvideo,
 body:not(.taking):not(.video) #start-takephoto,
 body:not(.timer):not(.video) #start-takephoto,
@@ -344,8 +350,6 @@
   background: var(--white);
   border-radius: 50%;
   height: var(--size);
-  /* match the position of photo shutter button */
-  margin: calc((72px - var(--size)) / 2);
   position: relative;
   width: var(--size);
 }
@@ -359,12 +363,10 @@
   --red: #d93025;
 }
 
-/* red dot */
-#recordvideo::before {
+#recordvideo .red-dot {
   background: var(--red);
   border-radius: 50%;
   box-sizing: border-box;
-  content: '';
   height: var(--dot-size);
   left: calc(50% - var(--dot-size) / 2);
   position: absolute;
@@ -373,18 +375,16 @@
   width: var(--dot-size);
 }
 
-body.taking.video #recordvideo::before {
+body.taking.video #recordvideo .red-dot {
   height: var(--size);
   left: 0;
   top: 0;
   width: var(--size);
 }
 
-/* white square */
-#recordvideo::after {
+#recordvideo .white-square {
   background: var(--white);
   border-radius: 2px;
-  content: '';
   height: 0;
   left: 50%;
   opacity: 0;
@@ -394,7 +394,7 @@
   width: 0;
 }
 
-body.taking.video #recordvideo::after {
+body.taking.video #recordvideo .white-square {
   height: var(--square-size);
   left: calc(50% - var(--square-size) / 2);
   opacity: 1;
@@ -464,10 +464,7 @@
 }
 
 body.tab-navigation #switch-device:focus::after {
-  bottom: -8px;
-  left: -8px;
-  right: -8px;
-  top: -8px;
+  --focus-ring-size: 8px;
 }
 
 #gallery-enter {
@@ -1122,7 +1119,7 @@
   transition: border-width 100ms ease-in;
 }
 
-body.tab-navigation .menu-item:focus::after {
+body.tab-navigation button.menu-item:focus::after {
   left: 2px;
   right: 2px;
 }
diff --git a/chrome/browser/resources/chromeos/camera/src/views/main.html b/chrome/browser/resources/chromeos/camera/src/views/main.html
index 122c90a9..6aa5884 100644
--- a/chrome/browser/resources/chromeos/camera/src/views/main.html
+++ b/chrome/browser/resources/chromeos/camera/src/views/main.html
@@ -72,7 +72,10 @@
       </div>
       <div id="shutters-group" class="buttons right-stripe circle">
         <button id="recordvideo" class="shutter" tabindex="0"
-                i18n-label="record_video_start_button"></button>
+                i18n-label="record_video_start_button">
+          <div class="red-dot"></div>
+          <div class="white-square"></div>
+        </button>
         <button id="start-takephoto" class="shutter" tabindex="0"
                 i18n-label="take_photo_button"></button>
         <button id="stop-takephoto" class="shutter" tabindex="0"
diff --git a/chrome/browser/resources/chromeos/crostini_installer/app.html b/chrome/browser/resources/chromeos/crostini_installer/app.html
index 7ca5185..475fb7f 100644
--- a/chrome/browser/resources/chromeos/crostini_installer/app.html
+++ b/chrome/browser/resources/chromeos/crostini_installer/app.html
@@ -121,19 +121,33 @@
           </div>
           <div>$i18n{diskSizeHint}</div>
         </div>
+        <template is="dom-if" if="[[!isLowSpaceAvailable_]]">
+          <cr-radio-group id="diskSizeRadio" selected="recommended"
+              on-selected-changed="onDiskSizeRadioChanged_">
+            <cr-radio-button name="recommended" id="recommended-size">
+              $i18n{recommendedDiskSizeLabel}
+            </cr-radio-button>
+            <cr-radio-button name="custom" id="custom-size">
+              $i18n{customDiskSizeLabel}
+            </cr-radio-button>
+          </cr-radio-group>
+        </template>
         <div id='low-free-space-warning' hidden="[[!isLowSpaceAvailable_]]">
           <iron-icon icon="cr:warning"></iron-icon>
           $i18n{lowSpaceAvailableWarning}
         </div>
-        <div class="outer">
-          <cr-slider id="diskSlider" pin="true" value="[[defaultDiskSizeTick_]]"
-              aria-describedby="disk-size-message" ticks="[[diskSizeTicks_]]">
-          </cr-slider>
-          <div id="labels">
-            <div id="label-begin">[[minDisk_]]</div>
-            <div id="label-end">[[maxDisk_]]</div>
+        <template is="dom-if" if="[[showDiskSlider_]]">
+          <div class="outer">
+            <cr-slider id="diskSlider" pin="true"
+                value="[[defaultDiskSizeTick_]]"
+                aria-describedby="disk-size-message" ticks="[[diskSizeTicks_]]">
+            </cr-slider>
+            <div id="labels">
+              <div id="label-begin">[[minDisk_]]</div>
+              <div id="label-end">[[maxDisk_]]</div>
+            </div>
           </div>
-        </div>
+        </template>
       </div>
     </div>
     <div id="installing-message" hidden="[[!eq_(state_, State.INSTALLING)]]">
diff --git a/chrome/browser/resources/chromeos/crostini_installer/app.js b/chrome/browser/resources/chromeos/crostini_installer/app.js
index 8ec7c7f..fab678c2 100644
--- a/chrome/browser/resources/chromeos/crostini_installer/app.js
+++ b/chrome/browser/resources/chromeos/crostini_installer/app.js
@@ -5,6 +5,8 @@
 import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
 import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
 import 'chrome://resources/cr_elements/cr_slider/cr_slider.m.js';
+import 'chrome://resources/cr_elements/cr_radio_group/cr_radio_group.m.js';
+import 'chrome://resources/cr_elements/cr_radio_button/cr_radio_button.m.js';
 import 'chrome://resources/cr_elements/icons.m.js';
 import 'chrome://resources/cr_elements/shared_vars_css.m.js';
 import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
@@ -137,6 +139,11 @@
       type: Boolean,
     },
 
+    showDiskSlider_: {
+      type: Boolean,
+      value: false,
+    },
+
     username_: {
       type: String,
       value: loadTimeData.getString('defaultContainerUsername')
@@ -165,14 +172,15 @@
       callbackRouter.onInstallFinished.addListener(error => {
         if (error === InstallerError.kNone) {
           // Install succeeded.
-          this.closeDialog_();
+          this.closePage_();
         } else {
           assert(this.state_ === State.INSTALLING);
           this.errorMessage_ = this.getErrorMessage_(error);
           this.state_ = State.ERROR;
         }
       }),
-      callbackRouter.onCanceled.addListener(() => this.closeDialog_()),
+      callbackRouter.onCanceled.addListener(() => this.closePage_()),
+      callbackRouter.requestClose.addListener(() => this.cancelOrBack_(true)),
     ];
 
     // TODO(lxj): The listener should only be invoked once, so it is fine to use
@@ -191,6 +199,9 @@
               this.maxDisk_ = ticks[ticks.length - 1].label;
 
               this.isLowSpaceAvailable_ = isLowSpaceAvailable;
+              if (isLowSpaceAvailable) {
+                this.showDiskSlider_ = true;
+              }
               resolve();
             }
           }));
@@ -198,7 +209,7 @@
 
     document.addEventListener('keyup', event => {
       if (event.key == 'Escape') {
-        this.onCancelButtonClick_();
+        this.cancelOrBack_();
         event.preventDefault();
       }
     });
@@ -244,7 +255,11 @@
     assert(this.showInstallButton_(this.state_));
     var diskSize = 0;
     if (loadTimeData.getBoolean('diskResizingEnabled')) {
-      diskSize = this.diskSizeTicks_[this.$.diskSlider.value].value;
+      if (this.showDiskSlider_) {
+        diskSize = this.diskSizeTicks_[this.$$('#diskSlider').value].value;
+      } else {
+        diskSize = this.diskSizeTicks_[this.defaultDiskSizeTick_].value;
+      }
     }
     this.installerState_ = InstallerState.kStart;
     this.installerProgress_ = 0;
@@ -252,15 +267,29 @@
     BrowserProxy.getInstance().handler.install(diskSize, this.username_);
   },
 
-  /** @private */
+  /**
+   * This is used in app.html so that the event argument is not passed to
+   * cancelOrBack_().
+   *
+   * @private
+   */
   onCancelButtonClick_() {
+    this.cancelOrBack_();
+  },
+
+  /** @private */
+  cancelOrBack_(forceCancel = false) {
     switch (this.state_) {
       case State.PROMPT:
         BrowserProxy.getInstance().handler.cancelBeforeStart();
-        this.closeDialog_();
+        this.closePage_();
         break;
       case State.CONFIGURE:
-        this.state_ = State.PROMPT;
+        if (forceCancel) {
+          this.closePage_();
+        } else {
+          this.state_ = State.PROMPT;
+        }
         break;
       case State.INSTALLING:
         this.state_ = State.CANCELING;
@@ -268,11 +297,11 @@
         break;
       case State.ERROR:
       case State.ERROR_NO_RETRY:
-        this.closeDialog_();
+        this.closePage_();
         break;
       case State.CANCELING:
         // Although cancel button has been disabled, we can reach here if users
-        // press <esc> key.
+        // press <esc> key or from mojom "RequestClose()".
         break;
       default:
         assertNotReached();
@@ -280,8 +309,8 @@
   },
 
   /** @private */
-  closeDialog_() {
-    BrowserProxy.getInstance().handler.close();
+  closePage_() {
+    BrowserProxy.getInstance().handler.onPageClosed();
   },
 
   /**
@@ -542,4 +571,13 @@
   showErrorMessage_(state) {
     return state === State.ERROR || state === State.ERROR_NO_RETRY;
   },
+
+  /** @private */
+  onDiskSizeRadioChanged_(event) {
+    if (this.$$('#diskSizeRadio')) {
+      this.showDiskSlider_ =
+          (this.$$('#diskSizeRadio').selected !== 'recommended' ||
+           !!this.isLowSpaceAvailable_);
+    }
+  }
 });
diff --git a/chrome/browser/resources/chromeos/crostini_upgrader/app.js b/chrome/browser/resources/chromeos/crostini_upgrader/app.js
index c7c86aef..7a2c4f4 100644
--- a/chrome/browser/resources/chromeos/crostini_upgrader/app.js
+++ b/chrome/browser/resources/chromeos/crostini_upgrader/app.js
@@ -190,8 +190,13 @@
           this.state_ = State.ERROR;
           return;
         }
-        this.closeDialog_();
+        this.closePage_();
       }),
+      callbackRouter.requestClose.addListener(() => {
+        if (this.canCancel_(this.state_)) {
+          this.onCancelButtonClick_();
+        }
+      })
     ];
 
     document.addEventListener('keyup', event => {
@@ -223,7 +228,7 @@
       case State.SUCCEEDED:
       case State.RESTORE_SUCCEEDED:
         BrowserProxy.getInstance().handler.launch();
-        this.closeDialog_();
+        this.closePage_();
         break;
       case State.PRECHECKS_FAILED:
         this.precheckThenUpgrade_();
@@ -255,7 +260,7 @@
       case State.ERROR:
       case State.OFFER_RESTORE:
       case State.SUCCEEDED:
-        this.closeDialog_();
+        this.closePage_();
         break;
       case State.CANCELING:
         break;
@@ -298,8 +303,8 @@
   },
 
   /** @private */
-  closeDialog_() {
-    BrowserProxy.getInstance().handler.close();
+  closePage_() {
+    BrowserProxy.getInstance().handler.onPageClosed();
   },
 
   /**
diff --git a/chrome/browser/resources/settings/autofill_page/BUILD.gn b/chrome/browser/resources/settings/autofill_page/BUILD.gn
index 8a430e0..7f50009 100644
--- a/chrome/browser/resources/settings/autofill_page/BUILD.gn
+++ b/chrome/browser/resources/settings/autofill_page/BUILD.gn
@@ -236,6 +236,7 @@
     ":passwords_list_handler",
     "..:global_scroll_target_behavior.m",
     "..:route",
+    "../people_page:profile_info_browser_proxy.m",
     "../people_page:sync_browser_proxy.m",
     "../prefs:prefs_behavior.m",
     "//third_party/polymer/v3_0/components-chromium/iron-a11y-announcer:iron-a11y-announcer",
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_section.html b/chrome/browser/resources/settings/autofill_page/passwords_section.html
index 8c1aeb4..a6924f1 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_section.html
+++ b/chrome/browser/resources/settings/autofill_page/passwords_section.html
@@ -44,6 +44,15 @@
                                     transparent 100%);
         }
       }
+
+      #profileIcon {
+        background: center / cover no-repeat;
+        border-radius: 20px;
+        flex-shrink: 0;
+        height: 40px;
+        margin-inline-end: 16px;
+        width: 40px;
+      }
    </style>
     <settings-toggle-button id="passwordToggle"
         aria-label="$i18n{passwords}" no-extension-indicator
@@ -118,17 +127,6 @@
       <!-- This div lays out the link correctly, relative to the text. -->
       <div class="cr-padded-text">$i18nRaw{managePasswordsLabel}</div>
     </div>
-    <div hidden$="[[!eligibleForAccountStorage_]]" class="cr-row"
-         id="accountStorageButtonsContainer">
-      <cr-button on-click="onOptIn_" id="optInToAccountStorageButton"
-          class="flex" hidden$="[[isOptedInForAccountStorage_]]">
-          $i18n{optInAccountStorageLabel}
-      </cr-button>
-      <cr-button on-click="onOptOut_" id="optOutOfAccountStorageButton"
-          class="flex" hidden$="[[!isOptedInForAccountStorage_]]">
-          $i18n{optOutAccountStorageLabel}
-      </cr-button>
-    </div>
     <div class="cr-row first">
       <h2 id="savedPasswordsHeading" class="flex">
         $i18n{savedPasswordsHeading}
@@ -150,6 +148,24 @@
 </if>
       should-show-storage-details="[[shouldShowStorageDetails_]]">
       <div slot="body" class="list-frame">
+        <div class="cr-row first two-line list-item"
+            hidden$="[[!eligibleForAccountStorage_]]"
+            id="accountStorageButtonsContainer">
+          <div id="profileIcon" style="background-image: [[profileIcon_]]">
+          </div>
+          <div class="flex cr-padded-text">
+            <div id="accountStorageBody"> [[accountStorageToggleBody_]] </div>
+            <div id="accountEmail" class="secondary">[[profileEmail_]]</div>
+          </div>
+          <cr-button on-click="onOptIn_" id="optInToAccountStorageButton"
+              hidden$="[[isOptedInForAccountStorage_]]">
+            $i18n{optInAccountStorageLabel}
+          </cr-button>
+          <cr-button on-click="onOptOut_" id="optOutOfAccountStorageButton"
+              hidden$="[[!isOptedInForAccountStorage_]]">
+            $i18n{optOutAccountStorageLabel}
+          </cr-button>
+        </div>
         <div id="savedPasswordsHeaders" class="list-item column-header"
             hidden$="[[!hasSavedPasswords_]]" aria-hidden="true">
           <div class="website-column">$i18n{editPasswordWebsiteLabel}</div>
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_section.js b/chrome/browser/resources/settings/autofill_page/passwords_section.js
index a6747c36..bea137b 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_section.js
+++ b/chrome/browser/resources/settings/autofill_page/passwords_section.js
@@ -24,12 +24,17 @@
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js';
 import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
+import {getImage} from 'chrome://resources/js/icon.m.js';
 import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
 import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
 import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js';
 import {IronA11yKeysBehavior} from 'chrome://resources/polymer/v3_0/iron-a11y-keys-behavior/iron-a11y-keys-behavior.js';
 import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js';
 import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
+
+// <if expr="chromeos">
+import {convertImageSequenceToPng} from 'chrome://resources/cr_elements/chromeos/cr_picture/png.m.js';
+// </if>
 import '../controls/extension_controlled_indicator.m.js';
 import '../controls/settings_toggle_button.m.js';
 import {GlobalScrollTargetBehavior} from '../global_scroll_target_behavior.m.js';
@@ -48,6 +53,7 @@
 import {PasswordManagerImpl, PasswordManagerProxy} from './password_manager_proxy.js';
 import './passwords_export_dialog.js';
 import './passwords_shared_css.js';
+import {ProfileInfo, ProfileInfoBrowserProxy, ProfileInfoBrowserProxyImpl} from '../people_page/profile_info_browser_proxy.m.js';
 // <if expr="chromeos">
 import '../controls/password_prompt_dialog.m.js';
 import {BlockingRequestManager} from './blocking_request_manager.js';
@@ -203,6 +209,26 @@
     },
 
     /** @private */
+    accountStorageToggleBody_: {
+      type: String,
+      value: '',
+      computed: 'computeAccountStorageToggleBody(isOptedInForAccountStorage_)',
+    },
+
+    /** @private */
+    profileEmail_: {
+      type: String,
+      value: '',
+      computed: 'getFirstStoredAccountEmail_(storedAccounts_)',
+    },
+
+    /**
+     * The currently selected profile icon as CSS image set.
+     * @private
+     */
+    profileIcon_: String,
+
+    /** @private */
     isOptedInForAccountStorage_: Boolean,
 
     /** @private {SyncPrefs} */
@@ -318,6 +344,13 @@
     syncBrowserProxy.sendSyncPrefsChanged();
     this.addWebUIListener('sync-prefs-changed', syncPrefsChanged);
 
+    /** @type {!ProfileInfoBrowserProxy} */ (
+        ProfileInfoBrowserProxyImpl.getInstance())
+        .getProfileInfo()
+        .then(this.extractImageFromProfileInfo_.bind(this));
+    this.addWebUIListener(
+        'profile-info-changed', this.extractImageFromProfileInfo_.bind(this));
+
     // For non-ChromeOS, also check whether accounts are available.
     // <if expr="not chromeos">
     const storedAccountsChanged = accounts => this.storedAccounts_ = accounts;
@@ -546,6 +579,27 @@
   },
 
   /**
+   * Updates the profile icon used in the opt-in/opt-out element based on the
+   * given profile info.
+   * @private
+   * @param {!ProfileInfo} info
+   */
+  extractImageFromProfileInfo_(info) {
+    /**
+     * Extract first frame from image by creating a single frame PNG using
+     * url as input if base64 encoded and potentially animated.
+     */
+    // <if expr="chromeos">
+    if (info.iconUrl.startsWith('data:image/png;base64')) {
+      this.profileIcon_ = getImage(convertImageSequenceToPng([info.iconUrl]));
+      return;
+    }
+    // </if>
+
+    this.profileIcon_ = getImage(info.iconUrl);
+  },
+
+  /**
    * @private
    * @return {boolean}
    */
@@ -568,4 +622,28 @@
   computeHasNeverCheckedPasswords_() {
     return !this.status.elapsedTimeSinceLastCheck;
   },
+
+  /**
+   * @private
+   * @return {string}
+   */
+  computeAccountStorageToggleBody() {
+    return this.isOptedInForAccountStorage_ ?
+        this.i18n('optOutAccountStorageBody') :
+        this.i18n('optInAccountStorageBody');
+  },
+
+  /**
+   * Return the first available stored account. This is useful when trying to
+   * figure out the account logged into the content area which seems to always
+   * be first even if multiple accounts are available.
+   * @return {string} The email address of the first stored account or an empty
+   *     string.
+   * @private
+   */
+  getFirstStoredAccountEmail_() {
+    return !!this.storedAccounts_ && this.storedAccounts_.length > 0 ?
+        this.storedAccounts_[0].email :
+        '';
+  },
 });
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_search_box/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_settings_search_box/BUILD.gn
index a206a3b..475fdd5 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_search_box/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/os_settings_search_box/BUILD.gn
@@ -34,6 +34,7 @@
     "//ui/webui/resources/js:i18n_behavior",
     "//ui/webui/resources/js/cr/ui:focus_row_behavior",
   ]
+  externs_list = [ "$externs_path/metrics_private.js" ]
 }
 
 # TODO: Uncomment as the Polymer3 migration makes progress.
@@ -51,6 +52,7 @@
     # TODO: Fill those in.
   ]
   extra_deps = [ ":os_search_result_row_module" ]
+  externs_list = [ "$externs_path/metrics_private.js" ]
 }
 
 js_library("os_settings_search_box.m") {
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.js b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.js
index b3682b1..82374ef 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.js
+++ b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.js
@@ -319,8 +319,44 @@
       }
     },
 
+    /** @private */
+    recordSearchResultMetrics_() {
+      const SearchResultType = chromeos.settings.mojom.SearchResultType;
+
+      chrome.metricsPrivate.recordEnumerationValue(
+          'ChromeOS.Settings.SearchResultTypeSelected', this.searchResult.type,
+          SearchResultType.MAX_VALUE);
+
+      const metricArgs = (type, id) => {
+        switch (type) {
+          case SearchResultType.kSection:
+            return {
+              metricName: 'ChromeOS.Settings.SearchResultSectionSelected',
+              value: id.section,
+            };
+          case SearchResultType.kSubpage:
+            return {
+              metricName: 'ChromeOS.Settings.SearchResultSubpageSelected',
+              value: id.subpage,
+            };
+          case SearchResultType.kSetting:
+            return {
+              metricName: 'ChromeOS.Settings.SearchResultSettingSelected',
+              value: id.setting,
+            };
+          default:
+            assertNotReached('Search Result Type not specified.');
+            return null;
+        }
+      };
+
+      const args = metricArgs(this.searchResult.type, this.searchResult.id);
+      chrome.metricsPrivate.recordSparseValue(args.metricName, args.value);
+    },
+
     navigateToSearchResultRoute() {
       assert(this.searchResult.urlPathWithParameters, 'Url path is empty.');
+      this.recordSearchResultMetrics_();
 
       // |this.searchResult.urlPathWithParameters| separates the path and params
       // by a '?' char.
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.html b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.html
index 85e7eb3..0ce7237 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.html
+++ b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.html
@@ -52,6 +52,11 @@
 
       :host(:focus-within) cr-toolbar-search-field {
         --cr-toolbar-search-field-background: var(--cr-card-background-color);
+        box-shadow: var(--cr-menu-shadow);
+      }
+
+      :host(:not(:focus-within)) cr-toolbar-search-field {
+        --cr-toolbar-search-field-cursor: pointer;
       }
 
       :host(:focus-within[should-show-dropdown_]) cr-toolbar-search-field {
@@ -60,14 +65,6 @@
         margin-top: var(--separator-height);
       }
 
-      :host(:not([should-show-dropdown_])) cr-toolbar-search-field {
-        --cr-toolbar-search-field-cursor: pointer;
-      };
-
-      :host(:focus-within) cr-toolbar-search-field {
-        box-shadow: var(--cr-menu-shadow);
-      }
-
       :host([narrow]) iron-dropdown {
         left: 0;
         margin-inline-end: 24px;
diff --git a/chrome/browser/resources/settings/controls/settings_radio_group.html b/chrome/browser/resources/settings/controls/settings_radio_group.html
index ff6a6759..ce838b4 100644
--- a/chrome/browser/resources/settings/controls/settings_radio_group.html
+++ b/chrome/browser/resources/settings/controls/settings_radio_group.html
@@ -11,7 +11,8 @@
     <style include="settings-shared"></style>
     <cr-radio-group selected="[[selected]]"
         on-selected-changed="onSelectedChanged_"
-        aria-label$="[[groupAriaLabel]]">
+        aria-label$="[[groupAriaLabel]]"
+        selectable-elements="[[selectableElements]]">
       <slot></slot>
     </cr-radio-group>
   </template>
diff --git a/chrome/browser/resources/settings/controls/settings_radio_group.js b/chrome/browser/resources/settings/controls/settings_radio_group.js
index 713382f..d15a91f 100644
--- a/chrome/browser/resources/settings/controls/settings_radio_group.js
+++ b/chrome/browser/resources/settings/controls/settings_radio_group.js
@@ -21,6 +21,11 @@
     groupAriaLabel: String,
 
     selected: String,
+
+    selectableElements: {
+      type: String,
+      value: ['cr-radio-button', 'controlled-radio-button'].join(', '),
+    },
   },
 
   hostAttributes: {
@@ -46,5 +51,6 @@
     this.set(
         'pref.value',
         Settings.PrefUtil.stringToPrefValue(this.selected, this.pref));
+    this.fire('change');
   },
 });
diff --git a/chrome/browser/resources/settings/privacy_page/collapse_radio_button.html b/chrome/browser/resources/settings/privacy_page/collapse_radio_button.html
index 7e0d4f86..fc617b3 100644
--- a/chrome/browser/resources/settings/privacy_page/collapse_radio_button.html
+++ b/chrome/browser/resources/settings/privacy_page/collapse_radio_button.html
@@ -8,6 +8,7 @@
       }
 
       cr-policy-indicator,
+      cr-policy-pref-indicator,
       :host([disabled]) cr-expand-button {
         pointer-events: auto;
       }
@@ -77,11 +78,19 @@
             <slot name="sub-label"></slot>
           </div>
         </div>
-        <cr-policy-indicator id="policyIndicator"
-            on-click="onIndicatorClick_"
-            on-aria-label="[[label]]"
-            indicator-type="[[policyIndicatorType]]">
-        </cr-policy-indicator>
+        <template is="dom-if" if="[[pref]]">
+          <cr-policy-pref-indicator pref="[[pref]]" icon-aria-label="[[label]]"
+            associated-value="[[name]]">
+          </cr-policy-pref-indicator>
+        </template>
+        <template is="dom-if"
+            if="[[shouldShowPolicyIndicator_(pref, policyIndicatorType)]]">
+          <cr-policy-indicator id="policyIndicator"
+              on-click="onIndicatorClick_"
+              on-aria-label="[[label]]"
+              indicator-type="[[policyIndicatorType]]">
+          </cr-policy-indicator>
+        </template>
         <div hidden$="[[noCollapse]]" class="separator"></div>
         <cr-expand-button hidden$="[[noCollapse]]" expanded="{{expanded}}">
         </cr-expand-button>
diff --git a/chrome/browser/resources/settings/privacy_page/collapse_radio_button.js b/chrome/browser/resources/settings/privacy_page/collapse_radio_button.js
index ad6e2f7..8b77b4a 100644
--- a/chrome/browser/resources/settings/privacy_page/collapse_radio_button.js
+++ b/chrome/browser/resources/settings/privacy_page/collapse_radio_button.js
@@ -41,13 +41,28 @@
 
     label: String,
 
+    /*
+     * The Preference associated with the radio group.
+     * @type {!chrome.settingsPrivate.PrefObject|undefined}
+     */
+    pref: Object,
+
+    disabled: {
+      type: Boolean,
+      value: false,
+      reflectToAttribute: true,
+    },
+
     subLabel: {
       type: String,
       value: '',  // Allows the $hidden= binding to run without being set.
     },
   },
 
-  observers: ['onCheckedChanged_(checked)'],
+  observers: [
+    'onCheckedChanged_(checked)',
+    'onPrefChanged_(pref.*)',
+  ],
 
   /** @private */
   onCheckedChanged_() {
@@ -63,4 +78,21 @@
     e.preventDefault();
     e.stopPropagation();
   },
+
+  /** @private */
+  onPrefChanged_() {
+    // If the preference has been set, and is managed, this control should be
+    // disabled. Unless the value associated with this control is present in
+    // |pref.userSelectableValues|. This will override the disabled set on the
+    // element externally.
+    this.disabled = !!this.pref &&
+        this.pref.enforcement === chrome.settingsPrivate.Enforcement.ENFORCED &&
+        !(!!this.pref.userSelectableValues &&
+          this.pref.userSelectableValues.includes(this.name));
+  },
+
+  /** @private */
+  shouldShowPolicyIndicator_() {
+    return !this.pref;
+  },
 });
diff --git a/chrome/browser/resources/settings/privacy_page/cookies_page.html b/chrome/browser/resources/settings/privacy_page/cookies_page.html
index 401c164e..c014800 100644
--- a/chrome/browser/resources/settings/privacy_page/cookies_page.html
+++ b/chrome/browser/resources/settings/privacy_page/cookies_page.html
@@ -42,15 +42,14 @@
     </picture>
     <div id="generalControls">
       <h2>$i18n{cookiePageGeneralControls}</h2>
-      <cr-radio-group selected="[[cookiesControlRadioSelected_]]"
+      <settings-radio-group id="primarySettingGroup"
+          pref="{{prefs.generated.cookie_primary_setting}}"
           selectable-elements="cr-radio-button, settings-collapse-radio-button"
-          on-selected-changed="onCookiesControlRadioChange_">
+          on-change="onCookiePrimarySettingChanged_">
         <settings-collapse-radio-button id="allowAll"
-            name="[[cookiesControlEnum_.ALLOW_ALL]]"
-            label="$i18n{cookiePageAllowAll}"
-            disabled="[[cookieControlsManagedState_.allowAll.disabled]]"
-            policy-indicator-type=
-                    "[[cookieControlsManagedState_.allowAll.indicator]]">
+            pref="[[prefs.generated.cookie_primary_setting]]"
+            name="[[cookiePrimarySettingEnum_.ALLOW_ALL]]"
+            label="$i18n{cookiePageAllowAll}">
           <div slot="collapse">
             <div class="bullet-line">
               <iron-icon icon="settings:cookie"></iron-icon>
@@ -64,14 +63,9 @@
         </settings-collapse-radio-button>
         <template is="dom-if" if="[[improvedCookieControlsEnabled_]]">
           <settings-collapse-radio-button id="blockThirdPartyIncognito"
-              name="[[cookiesControlEnum_.BLOCK_THIRD_PARTY_INCOGNITO]]"
-              label="$i18n{cookiePageBlockThirdIncognito}"
-              disabled="[[
-                  cookieControlsManagedState_.blockThirdPartyIncognito.disabled
-                  ]]"
-              policy-indicator-type="[[
-                  cookieControlsManagedState_.blockThirdPartyIncognito.indicator
-                  ]]">
+              pref="[[prefs.generated.cookie_primary_setting]]"
+              name="[[cookiePrimarySettingEnum_.BLOCK_THIRD_PARTY_INCOGNITO]]"
+              label="$i18n{cookiePageBlockThirdIncognito}">
             <div slot="collapse">
               <div class="bullet-line">
                 <iron-icon icon="settings:cookie"></iron-icon>
@@ -89,11 +83,9 @@
           </settings-collapse-radio-button>
         </template>
         <settings-collapse-radio-button id="blockThirdParty"
-            name="[[cookiesControlEnum_.BLOCK_THIRD_PARTY]]"
-            label="$i18n{cookiePageBlockThird}"
-            disabled="[[cookieControlsManagedState_.blockThirdParty.disabled]]"
-            policy-indicator-type="[[
-                cookieControlsManagedState_.blockThirdParty.indicator]]">
+            pref="[[prefs.generated.cookie_primary_setting]]"
+            name="[[cookiePrimarySettingEnum_.BLOCK_THIRD_PARTY]]"
+            label="$i18n{cookiePageBlockThird}">
           <div slot="collapse">
             <div class="bullet-line">
               <iron-icon icon="settings:cookie"></iron-icon>
@@ -106,11 +98,9 @@
           </div>
         </settings-collapse-radio-button>
         <settings-collapse-radio-button id="blockAll"
-            name="[[cookiesControlEnum_.BLOCK_ALL]]"
-            label="$i18n{cookiePageBlockAll}"
-            disabled="[[cookieControlsManagedState_.blockAll.disabled]]"
-            policy-indicator-type="[[
-                cookieControlsManagedState_.blockAll.indicator]]">
+            pref="[[blockAllPref_]]"
+            name="[[cookiePrimarySettingEnum_.BLOCK_ALL]]"
+            label="$i18n{cookiePageBlockAll}">
           <div slot="collapse">
             <div class="bullet-line">
               <iron-icon icon="settings:block"></iron-icon>
@@ -126,7 +116,7 @@
             </div>
           </div>
         </settings-collapse-radio-button>
-      </cr-radio-group>
+      </settings-radio-group>
     </div>
     <settings-toggle-button id="clearOnExit" class="hr"
         pref="{{prefs.generated.cookie_session_only}}"
diff --git a/chrome/browser/resources/settings/privacy_page/cookies_page.js b/chrome/browser/resources/settings/privacy_page/cookies_page.js
index 215a3aec..6f1e4c4b 100644
--- a/chrome/browser/resources/settings/privacy_page/cookies_page.js
+++ b/chrome/browser/resources/settings/privacy_page/cookies_page.js
@@ -29,18 +29,19 @@
 import {PrefsBehavior} from '../prefs/prefs_behavior.m.js';
 import {routes} from '../route.js';
 import {Router} from '../router.m.js';
-import {ContentSetting, ContentSettingsTypes, CookieControlsMode, SiteSettingSource} from '../site_settings/constants.js';
-import {ContentSettingProvider, CookieControlsManagedState, DefaultContentSetting, SiteSettingsPrefsBrowserProxy, SiteSettingsPrefsBrowserProxyImpl} from '../site_settings/site_settings_prefs_browser_proxy.js';
+import {ContentSetting, ContentSettingsTypes} from '../site_settings/constants.js';
 
 /**
- * Enumeration of all cookies radio controls.
- * @enum {string}
+ * The primary cookie setting associated with each radio button. Must be kept in
+ * sync with the C++ enum of the same name in
+ * chrome/browser/content_settings/generated_cookie_prefs.h
+ * @enum {number}
  */
-const CookiesControl = {
-  ALLOW_ALL: 'allow-all',
-  BLOCK_THIRD_PARTY_INCOGNITO: 'block-third-party-incognito',
-  BLOCK_THIRD_PARTY: 'block-third-party',
-  BLOCK_ALL: 'block-all',
+const CookiePrimarySetting = {
+  ALLOW_ALL: 0,
+  BLOCK_THIRD_PARTY_INCOGNITO: 1,
+  BLOCK_THIRD_PARTY: 2,
+  BLOCK_ALL: 3,
 };
 
 /**
@@ -81,17 +82,14 @@
     },
 
     /**
-     * Valid cookie states.
+     * Primary cookie control states for use in bindings.
      * @private
      */
-    cookiesControlEnum_: {
+    cookiePrimarySettingEnum_: {
       type: Object,
-      value: CookiesControl,
+      value: CookiePrimarySetting,
     },
 
-    /** @private */
-    cookiesControlRadioSelected_: String,
-
     /**
      * Used for HTML bindings. This is defined as a property rather than
      * within the ready callback, because the value needs to be available
@@ -118,19 +116,10 @@
       value: ContentSettingsTypes.COOKIES,
     },
 
-    /**
-     * Whether the cookie content setting is managed.
-     * @private
-     */
-    cookiesContentSettingManaged_: {
+    /** @private */
+    exceptionListsReadOnly_: {
       type: Boolean,
-      notify: false,
-    },
-
-    /** @private {!CookieControlsManagedState} */
-    cookieControlsManagedState_: {
-      type: Object,
-      notify: true,
+      value: false,
     },
 
     /** @private */
@@ -141,6 +130,14 @@
       }
     },
 
+    /** @private {!chrome.settingsPrivate.PrefObject} */
+    blockAllPref_: {
+      type: Object,
+      value() {
+        return /** @type {chrome.settingsPrivate.PrefObject} */ ({});
+      },
+    },
+
     /** @type {!Map<string, (string|Function)>} */
     focusConfig: {
       type: Object,
@@ -148,32 +145,15 @@
     },
   },
 
-  observers: [
-    'updateCookiesControls_(prefs.profile.cookie_controls_mode,' +
-        'prefs.profile.block_third_party_cookies)',
-  ],
-
-  /** @type {?SiteSettingsPrefsBrowserProxy} */
-  browserProxy_: null,
+  observers: [`onGeneratedPrefsUpdated_(prefs.generated.cookie_session_only,
+      prefs.generated.cookie_primary_setting)`],
 
   /** @type {?MetricsBrowserProxy} */
   metricsBrowserProxy_: null,
 
   /** @override */
-  created() {
-    // Used during property initialisation so must be set in created.
-    this.browserProxy_ = SiteSettingsPrefsBrowserProxyImpl.getInstance();
-  },
-
-  /** @override */
   ready() {
     this.metricsBrowserProxy_ = MetricsBrowserProxyImpl.getInstance();
-
-    this.addWebUIListener('contentSettingCategoryChanged', category => {
-      if (category === ContentSettingsTypes.COOKIES) {
-        this.updateCookiesControls_();
-      }
-    });
   },
 
   /*
@@ -194,131 +174,45 @@
     Router.getInstance().navigateTo(routes.SITE_SETTINGS_SITE_DATA);
   },
 
-  /**
-   * Updates the cookies control radio toggle to represent the current cookie
-   * state.
-   * @private
-   */
-  async updateCookiesControls_() {
-    const controlMode = this.getPref('profile.cookie_controls_mode');
-    const blockThirdParty = this.getPref('profile.block_third_party_cookies');
-    const contentSetting =
-        await this.browserProxy_.getDefaultValueForContentType(
-            ContentSettingsTypes.COOKIES);
+  /** @private */
+  onGeneratedPrefsUpdated_() {
+    const sessionOnlyPref = this.getPref('generated.cookie_session_only');
 
-    // Set control state.
-    if (contentSetting.setting === ContentSetting.BLOCK) {
-      this.cookiesControlRadioSelected_ = CookiesControl.BLOCK_ALL;
-    } else if (blockThirdParty.value) {
-      this.cookiesControlRadioSelected_ =
-          this.cookiesControlEnum_.BLOCK_THIRD_PARTY;
-    } else if (
-        this.improvedCookieControlsEnabled_ &&
-        controlMode.value === CookieControlsMode.INCOGNITO_ONLY) {
-      this.cookiesControlRadioSelected_ =
-          this.cookiesControlEnum_.BLOCK_THIRD_PARTY_INCOGNITO;
-    } else {
-      this.cookiesControlRadioSelected_ = CookiesControl.ALLOW_ALL;
-    }
+    // If the clear on exit toggle is managed this implies a content setting
+    // policy is present and the exception lists should be disabled.
+    this.exceptionListsReadOnly_ = sessionOnlyPref.enforcement ==
+        chrome.settingsPrivate.Enforcement.ENFORCED;
 
-    // Set the exception lists to read only if the content setting is managed.
-    // Display of managed state for individual entries will be handled by each
-    // site-list-entry.
-    this.exceptionListsReadOnly_ =
-        contentSetting.source === SiteSettingSource.POLICY;
-
-    // Retrieve and update remaining controls managed state.
-    this.cookieControlsManagedState_ =
-        await this.browserProxy_.getCookieControlsManagedState();
+    // It is not currently possible to represent multiple management sources
+    // for a single a preference. In all management scenarios, the blockAll
+    // setting shares the same controlledBy as the cookie_session_only pref.
+    // To support this, the controlledBy fields for the |cookie_primary_setting|
+    // pref provided to the blockAll control are overwritten with values from
+    // the session_only preference.
+    this.set(
+        'blockAllPref_',
+        Object.assign(this.getPref('generated.cookie_primary_setting'), {
+          controlledBy: sessionOnlyPref.controlledBy,
+          controlledByName: sessionOnlyPref.controlledByName
+        }));
   },
 
   /**
-   * Get an appropriate pref source for a DefaultContentSetting.
-   * @param {!DefaultContentSetting} provider
-   * @return {!chrome.settingsPrivate.ControlledBy}
+   * Record interaction metrics for the primary cookie radio setting.
    * @private
    */
-  getControlledBy_({source}) {
-    switch (source) {
-      case ContentSettingProvider.POLICY:
-        return chrome.settingsPrivate.ControlledBy.DEVICE_POLICY;
-      case ContentSettingProvider.SUPERVISED_USER:
-        return chrome.settingsPrivate.ControlledBy.PARENT;
-      case ContentSettingProvider.EXTENSION:
-        return chrome.settingsPrivate.ControlledBy.EXTENSION;
-      default:
-        return chrome.settingsPrivate.ControlledBy.USER_POLICY;
-    }
-  },
-
-  /**
-   * Get an appropriate pref enforcement setting for a DefaultContentSetting.
-   * @param {!DefaultContentSetting} provider
-   * @return {!chrome.settingsPrivate.Enforcement|undefined}
-   * @private
-   */
-  getEnforced_({source}) {
-    switch (source) {
-      case ContentSettingProvider.POLICY:
-        return chrome.settingsPrivate.Enforcement.ENFORCED;
-      case ContentSettingProvider.SUPERVISED_USER:
-        return chrome.settingsPrivate.Enforcement.PARENT_SUPERVISED;
-      default:
-        return undefined;
-    }
-  },
-
-  /**
-   * @return {!ContentSetting}
-   * @private
-   */
-  computeClearOnExitSetting_() {
-    return this.$.clearOnExit.checked ? ContentSetting.SESSION_ONLY :
-                                        ContentSetting.ALLOW;
-  },
-
-  /**
-   * Set required preferences base on control mode and content setting.
-   * @param {!CookieControlsMode} controlsMode
-   * @param {!ContentSetting} contentSetting
-   * @private
-   */
-  setAllPrefs_(controlsMode, contentSetting) {
-    this.setPrefValue('profile.cookie_controls_mode', controlsMode);
-    this.setPrefValue(
-        'profile.block_third_party_cookies',
-        controlsMode == CookieControlsMode.BLOCK_THIRD_PARTY);
-    this.browserProxy_.setDefaultValueForContentType(
-        ContentSettingsTypes.COOKIES, contentSetting);
-  },
-
-  /**
-   * Updates the various underlying cookie prefs and content settings
-   * based on the newly selected radio button.
-   * @param {!CustomEvent<{value:!CookiesControl}>} event
-   * @private
-   */
-  onCookiesControlRadioChange_(event) {
-    if (event.detail.value === CookiesControl.ALLOW_ALL) {
-      this.setAllPrefs_(
-          CookieControlsMode.OFF, this.computeClearOnExitSetting_());
+  onCookiePrimarySettingChanged_() {
+    const selection = Number(this.$.primarySettingGroup.selected);
+    if (selection === CookiePrimarySetting.ALLOW_ALL) {
       this.metricsBrowserProxy_.recordSettingsPageHistogram(
           PrivacyElementInteractions.COOKIES_ALL);
-    } else if (
-        event.detail.value === CookiesControl.BLOCK_THIRD_PARTY_INCOGNITO) {
-      this.setAllPrefs_(
-          CookieControlsMode.INCOGNITO_ONLY, this.computeClearOnExitSetting_());
+    } else if (selection === CookiePrimarySetting.BLOCK_THIRD_PARTY_INCOGNITO) {
       this.metricsBrowserProxy_.recordSettingsPageHistogram(
           PrivacyElementInteractions.COOKIES_INCOGNITO);
-    } else if (event.detail.value === CookiesControl.BLOCK_THIRD_PARTY) {
-      this.setAllPrefs_(
-          CookieControlsMode.BLOCK_THIRD_PARTY,
-          this.computeClearOnExitSetting_());
+    } else if (selection === CookiePrimarySetting.BLOCK_THIRD_PARTY) {
       this.metricsBrowserProxy_.recordSettingsPageHistogram(
           PrivacyElementInteractions.COOKIES_THIRD);
-    } else {  // CookiesControl.BLOCK_ALL
-      this.setAllPrefs_(
-          CookieControlsMode.BLOCK_THIRD_PARTY, ContentSetting.BLOCK);
+    } else {  // CookiePrimarySetting.BLOCK_ALL
       this.metricsBrowserProxy_.recordSettingsPageHistogram(
           PrivacyElementInteractions.COOKIES_BLOCK);
     }
diff --git a/chrome/browser/resources/settings/safety_check_page/BUILD.gn b/chrome/browser/resources/settings/safety_check_page/BUILD.gn
index ad5849c..bf337dd 100644
--- a/chrome/browser/resources/settings/safety_check_page/BUILD.gn
+++ b/chrome/browser/resources/settings/safety_check_page/BUILD.gn
@@ -12,6 +12,7 @@
   deps = [
     ":safety_check_browser_proxy",
     ":safety_check_child",
+    ":safety_check_chrome_cleaner_child",
     ":safety_check_extensions_child",
     ":safety_check_page",
     ":safety_check_passwords_child",
@@ -32,6 +33,18 @@
   ]
 }
 
+js_library("safety_check_chrome_cleaner_child") {
+  deps = [
+    ":safety_check_child",
+    "..:metrics_browser_proxy",
+    "..:route",
+    "..:router.m",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/js:assert.m",
+    "//ui/webui/resources/js:web_ui_listener_behavior.m",
+  ]
+}
+
 js_library("safety_check_extensions_child") {
   deps = [
     ":safety_check_child",
@@ -46,6 +59,7 @@
 js_library("safety_check_page") {
   deps = [
     ":safety_check_browser_proxy",
+    ":safety_check_chrome_cleaner_child",
     ":safety_check_extensions_child",
     ":safety_check_passwords_child",
     ":safety_check_safe_browsing_child",
@@ -102,6 +116,7 @@
 html_to_js("web_components") {
   js_files = [
     "safety_check_child.js",
+    "safety_check_chrome_cleaner_child.js",
     "safety_check_extensions_child.js",
     "safety_check_page.js",
     "safety_check_passwords_child.js",
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_browser_proxy.js b/chrome/browser/resources/settings/safety_check_page/safety_check_browser_proxy.js
index b72776c..f400785 100644
--- a/chrome/browser/resources/settings/safety_check_page/safety_check_browser_proxy.js
+++ b/chrome/browser/resources/settings/safety_check_page/safety_check_browser_proxy.js
@@ -23,6 +23,7 @@
   PASSWORDS_CHANGED: 'safety-check-passwords-status-changed',
   SAFE_BROWSING_CHANGED: 'safety-check-safe-browsing-status-changed',
   EXTENSIONS_CHANGED: 'safety-check-extensions-status-changed',
+  CHROME_CLEANER_CHANGED: 'safety-check-chrome-cleaner-status-changed',
 };
 
 /**
@@ -105,6 +106,32 @@
   BLOCKLISTED_REENABLED_ALL_BY_ADMIN: 6,
 };
 
+/**
+ * States of the safety check Chrome cleaner element.
+ * Needs to be kept in sync with ChromeCleanerStatus in
+ * chrome/browser/ui/webui/settings/safety_check_handler.h
+ * @enum {number}
+ */
+export const SafetyCheckChromeCleanerStatus = {
+  CHECKING: 0,
+  INITIAL: 1,
+  REPORTER_FOUND_NOTHING: 2,
+  REPORTER_FAILED: 3,
+  SCANNING_FOUND_NOTHING: 4,
+  SCANNING_FAILED: 5,
+  CONNECTION_LOST: 6,
+  USER_DECLINED_CLEANUP: 7,
+  CLEANING_FAILED: 8,
+  CLEANING_SUCCEEDED: 9,
+  CLEANER_DOWNLOAD_FAILED: 10,
+  REPORTER_RUNNING: 11,
+  SCANNING: 12,
+  INFECTED: 13,
+  CLEANING: 14,
+  REBOOT_REQUIRED: 15,
+  DISABLED_BY_ADMIN: 16,
+};
+
 /** @interface */
 export class SafetyCheckBrowserProxy {
   /** Run the safety check. */
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.html b/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.html
new file mode 100644
index 0000000..93cfbc7
--- /dev/null
+++ b/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.html
@@ -0,0 +1,10 @@
+<settings-safety-check-child
+    id="safetyCheckChild"
+    icon-status="[[getIconStatus_(status_)]]"
+    label="$i18n{safetyCheckChromeCleanerPrimaryLabel}"
+    sub-label="[[displayString_]]"
+    button-label="[[getButtonLabel_(status_)]]"
+    button-aria-label="[[getButtonAriaLabel_(status_)]]"
+    button-class="[[getButtonClass_(status_)]]"
+    on-button-click="onButtonClick_">
+</settings-safety-check-child>
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.js b/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.js
new file mode 100644
index 0000000..815dd0d
--- /dev/null
+++ b/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.js
@@ -0,0 +1,195 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview
+ * 'settings-safety-passwords-child' is the settings page containing the
+ * safety check child showing the password status.
+ */
+import {assertNotReached} from 'chrome://resources/js/assert.m.js';
+import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
+import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {MetricsBrowserProxy, MetricsBrowserProxyImpl, SafetyCheckInteractions} from '../metrics_browser_proxy.js';
+import {routes} from '../route.js';
+import {Router} from '../router.m.js';
+
+import {SafetyCheckCallbackConstants, SafetyCheckChromeCleanerStatus} from './safety_check_browser_proxy.js';
+import {SafetyCheckIconStatus} from './safety_check_child.js';
+
+/**
+ * @typedef {{
+ *   newState: SafetyCheckChromeCleanerStatus,
+ *   displayString: string,
+ * }}
+ */
+let ChromeCleanerChangedEvent;
+
+Polymer({
+  is: 'settings-safety-check-chrome-cleaner-child',
+
+  _template: html`{__html_template__}`,
+
+  behaviors: [
+    I18nBehavior,
+    WebUIListenerBehavior,
+  ],
+
+  properties: {
+    /**
+     * Current state of the safety check Chrome cleaner child.
+     * @private {!SafetyCheckChromeCleanerStatus}
+     */
+    status_: {
+      type: Number,
+      value: SafetyCheckChromeCleanerStatus.CHECKING,
+    },
+
+    /**
+     * UI string to display for this child, received from the backend.
+     * @private
+     */
+    displayString_: String,
+  },
+
+  /** @private {?MetricsBrowserProxy} */
+  metricsBrowserProxy_: null,
+
+  /** @override */
+  attached: function() {
+    this.metricsBrowserProxy_ = MetricsBrowserProxyImpl.getInstance();
+
+    // Register for safety check status updates.
+    this.addWebUIListener(
+        SafetyCheckCallbackConstants.CHROME_CLEANER_CHANGED,
+        this.onSafetyCheckChromeCleanerChanged_.bind(this));
+  },
+
+  /**
+   * @param {!ChromeCleanerChangedEvent} event
+   * @private
+   */
+  onSafetyCheckChromeCleanerChanged_: function(event) {
+    this.status_ = event.newState;
+    this.displayString_ = event.displayString;
+  },
+
+  /**
+   * @return {SafetyCheckIconStatus}
+   * @private
+   */
+  getIconStatus_: function() {
+    switch (this.status_) {
+      case SafetyCheckChromeCleanerStatus.CHECKING:
+        return SafetyCheckIconStatus.RUNNING;
+      case SafetyCheckChromeCleanerStatus.INITIAL:
+      case SafetyCheckChromeCleanerStatus.REPORTER_FOUND_NOTHING:
+      case SafetyCheckChromeCleanerStatus.SCANNING_FOUND_NOTHING:
+      case SafetyCheckChromeCleanerStatus.CLEANING_SUCCEEDED:
+      case SafetyCheckChromeCleanerStatus.REPORTER_RUNNING:
+      case SafetyCheckChromeCleanerStatus.SCANNING:
+        return SafetyCheckIconStatus.SAFE;
+      case SafetyCheckChromeCleanerStatus.REPORTER_FAILED:
+      case SafetyCheckChromeCleanerStatus.SCANNING_FAILED:
+      case SafetyCheckChromeCleanerStatus.CONNECTION_LOST:
+      case SafetyCheckChromeCleanerStatus.CLEANING_FAILED:
+      case SafetyCheckChromeCleanerStatus.CLEANER_DOWNLOAD_FAILED:
+      case SafetyCheckChromeCleanerStatus.CLEANING:
+      case SafetyCheckChromeCleanerStatus.REBOOT_REQUIRED:
+      case SafetyCheckChromeCleanerStatus.DISABLED_BY_ADMIN:
+        return SafetyCheckIconStatus.INFO;
+      case SafetyCheckChromeCleanerStatus.USER_DECLINED_CLEANUP:
+      case SafetyCheckChromeCleanerStatus.INFECTED:
+        return SafetyCheckIconStatus.WARNING;
+      default:
+        assertNotReached();
+    }
+  },
+
+  /**
+   * @private
+   * @return {?string}
+   */
+  getButtonLabel_: function() {
+    switch (this.status_) {
+      case SafetyCheckChromeCleanerStatus.REPORTER_FAILED:
+      case SafetyCheckChromeCleanerStatus.SCANNING_FAILED:
+      case SafetyCheckChromeCleanerStatus.CONNECTION_LOST:
+      case SafetyCheckChromeCleanerStatus.USER_DECLINED_CLEANUP:
+      case SafetyCheckChromeCleanerStatus.CLEANING_FAILED:
+      case SafetyCheckChromeCleanerStatus.CLEANER_DOWNLOAD_FAILED:
+      case SafetyCheckChromeCleanerStatus.INFECTED:
+      case SafetyCheckChromeCleanerStatus.CLEANING:
+        return this.i18n('safetyCheckReview');
+      case SafetyCheckChromeCleanerStatus.REBOOT_REQUIRED:
+        return this.i18n('chromeCleanupRestartButtonLabel');
+      default:
+        return null;
+    }
+  },
+
+  /**
+   * @private
+   * @return {?string}
+   */
+  getButtonAriaLabel_: function() {
+    switch (this.status_) {
+      case SafetyCheckChromeCleanerStatus.REPORTER_FAILED:
+      case SafetyCheckChromeCleanerStatus.SCANNING_FAILED:
+      case SafetyCheckChromeCleanerStatus.CONNECTION_LOST:
+      case SafetyCheckChromeCleanerStatus.USER_DECLINED_CLEANUP:
+      case SafetyCheckChromeCleanerStatus.CLEANING_FAILED:
+      case SafetyCheckChromeCleanerStatus.CLEANER_DOWNLOAD_FAILED:
+      case SafetyCheckChromeCleanerStatus.INFECTED:
+      case SafetyCheckChromeCleanerStatus.CLEANING:
+        return this.i18n('safetyCheckChromeCleanerButtonAriaLabel');
+      case SafetyCheckChromeCleanerStatus.REBOOT_REQUIRED:
+        return this.i18n('chromeCleanupRestartButtonLabel');
+      default:
+        return null;
+    }
+  },
+
+  /**
+   * @private
+   * @return {string}
+   */
+  getButtonClass_: function() {
+    switch (this.status_) {
+      case SafetyCheckChromeCleanerStatus.USER_DECLINED_CLEANUP:
+      case SafetyCheckChromeCleanerStatus.INFECTED:
+      case SafetyCheckChromeCleanerStatus.REBOOT_REQUIRED:
+        return 'action-button';
+      default:
+        return '';
+    }
+  },
+
+  /** @private */
+  onButtonClick_: function() {
+    // TODO(crbug.com/1087263): Add metrics for safety check CCT child user
+    // actions.
+    switch (this.status_) {
+      case SafetyCheckChromeCleanerStatus.REPORTER_FAILED:
+      case SafetyCheckChromeCleanerStatus.SCANNING_FAILED:
+      case SafetyCheckChromeCleanerStatus.CONNECTION_LOST:
+      case SafetyCheckChromeCleanerStatus.USER_DECLINED_CLEANUP:
+      case SafetyCheckChromeCleanerStatus.CLEANING_FAILED:
+      case SafetyCheckChromeCleanerStatus.CLEANER_DOWNLOAD_FAILED:
+      case SafetyCheckChromeCleanerStatus.INFECTED:
+      case SafetyCheckChromeCleanerStatus.CLEANING:
+        Router.getInstance().navigateTo(
+            routes.CHROME_CLEANUP,
+            /* dynamicParams */ null, /* removeSearch */ true);
+        break;
+      case SafetyCheckChromeCleanerStatus.REBOOT_REQUIRED:
+        // TODO(crbug.com/1087263): Implement CCT-based reboot here.
+        break;
+      default:
+        // This is a state without an action.
+        break;
+    }
+  },
+});
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_page.html b/chrome/browser/resources/settings/safety_check_page/safety_check_page.html
index 8e852b84..073bcf45 100644
--- a/chrome/browser/resources/settings/safety_check_page/safety_check_page.html
+++ b/chrome/browser/resources/settings/safety_check_page/safety_check_page.html
@@ -45,4 +45,11 @@
       </settings-safety-check-safe-browsing-child>
       <settings-safety-check-extensions-child>
       </settings-safety-check-extensions-child>
+<if expr="_google_chrome and is_win">
+      <template is="dom-if" if="[[showChromeCleanerChild_(parentStatus_)]]"
+          restamp>
+        <settings-safety-check-chrome-cleaner-child>
+        </settings-safety-check-chrome-cleaner-child>
+      </template>
+</if>
     </iron-collapse>
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_page.js b/chrome/browser/resources/settings/safety_check_page/safety_check_page.js
index c7cb7b78..a3e8be2 100644
--- a/chrome/browser/resources/settings/safety_check_page/safety_check_page.js
+++ b/chrome/browser/resources/settings/safety_check_page/safety_check_page.js
@@ -17,6 +17,7 @@
 import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
 import '../settings_shared_css.m.js';
 import './safety_check_extensions_child.js';
+import './safety_check_chrome_cleaner_child.js';
 import './safety_check_passwords_child.js';
 import './safety_check_safe_browsing_child.js';
 import './safety_check_updates_child.js';
@@ -180,4 +181,13 @@
   shouldShowChildren_: function() {
     return this.parentStatus_ != SafetyCheckParentStatus.BEFORE;
   },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  showChromeCleanerChild_: function() {
+    return loadTimeData.valueExists('privacySettingsRedesignEnabled') &&
+        loadTimeData.getBoolean('privacySettingsRedesignEnabled');
+  },
 });
diff --git a/chrome/browser/resources/settings/settings.gni b/chrome/browser/resources/settings/settings.gni
index 48e79e5..0ecbe15 100644
--- a/chrome/browser/resources/settings/settings.gni
+++ b/chrome/browser/resources/settings/settings.gni
@@ -97,6 +97,7 @@
   "settings.MetricsReporting|MetricsReporting",
   "settings.SafetyCheckBrowserProxy|SafetyCheckBrowserProxy",
   "settings.SafetyCheckCallbackConstants|SafetyCheckCallbackConstants",
+  "settings.SafetyCheckChromeCleanerStatus|SafetyCheckChromeCleanerStatus",
   "settings.SafetyCheckExtensionsStatus|SafetyCheckExtensionsStatus",
   "settings.SafetyCheckIconStatus|SafetyCheckIconStatus",
   "settings.SafetyCheckParentStatus|SafetyCheckParentStatus",
diff --git a/chrome/browser/resources/settings/settings.js b/chrome/browser/resources/settings/settings.js
index f4499b6..5d7d382 100644
--- a/chrome/browser/resources/settings/settings.js
+++ b/chrome/browser/resources/settings/settings.js
@@ -34,7 +34,7 @@
 export {ResetBrowserProxyImpl} from './reset_page/reset_browser_proxy.js';
 export {buildRouter, routes} from './route.js';
 export {Route, Router} from './router.m.js';
-export {SafetyCheckBrowserProxy, SafetyCheckBrowserProxyImpl, SafetyCheckCallbackConstants, SafetyCheckExtensionsStatus, SafetyCheckParentStatus, SafetyCheckPasswordsStatus, SafetyCheckSafeBrowsingStatus, SafetyCheckUpdatesStatus} from './safety_check_page/safety_check_browser_proxy.js';
+export {SafetyCheckBrowserProxy, SafetyCheckBrowserProxyImpl, SafetyCheckCallbackConstants, SafetyCheckChromeCleanerStatus, SafetyCheckExtensionsStatus, SafetyCheckParentStatus, SafetyCheckPasswordsStatus, SafetyCheckSafeBrowsingStatus, SafetyCheckUpdatesStatus} from './safety_check_page/safety_check_browser_proxy.js';
 export {SafetyCheckIconStatus} from './safety_check_page/safety_check_child.js';
 export {SearchEngine, SearchEnginesBrowserProxy, SearchEnginesBrowserProxyImpl, SearchEnginesInfo} from './search_engines_page/search_engines_browser_proxy.m.js';
 export {getSearchManager, SearchRequest, setSearchManagerForTesting} from './search_settings.m.js';
diff --git a/chrome/browser/resources/settings/settings_resources_v3.grdp b/chrome/browser/resources/settings/settings_resources_v3.grdp
index 839760a..a64b281 100644
--- a/chrome/browser/resources/settings/settings_resources_v3.grdp
+++ b/chrome/browser/resources/settings/settings_resources_v3.grdp
@@ -570,6 +570,10 @@
            file="${root_gen_dir}/chrome/browser/resources/settings/safety_check_page/safety_check_child.js"
            use_base_dir="false"
            compress="false" type="BINDATA" />
+  <include name="IDR_SETTINGS_SAFETY_CHECK_PAGE_SAFETY_CHECK_CHROME_CLEANER_CHILD_JS"
+           file="${root_gen_dir}/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.js"
+           use_base_dir="false"
+           compress="false" type="BINDATA" />
   <include name="IDR_SETTINGS_SAFETY_CHECK_PAGE_SAFETY_CHECK_EXTENSIONS_CHILD_JS"
            file="${root_gen_dir}/chrome/browser/resources/settings/safety_check_page/safety_check_extensions_child.js"
            use_base_dir="false"
diff --git a/chrome/browser/safety_check/android/BUILD.gn b/chrome/browser/safety_check/android/BUILD.gn
index cda0a96..574d52a 100644
--- a/chrome/browser/safety_check/android/BUILD.gn
+++ b/chrome/browser/safety_check/android/BUILD.gn
@@ -4,16 +4,63 @@
 
 import("//build/config/android/rules.gni")
 
+generate_jni("jni_headers") {
+  sources = [
+    "java/src/org/chromium/chrome/browser/safety_check/SafetyCheckBridge.java",
+  ]
+}
+
+source_set("android") {
+  sources = [
+    "safety_check_bridge.cc",
+    "safety_check_bridge.h",
+  ]
+  deps = [
+    ":jni_headers",
+    "//components/prefs",
+    "//components/safety_check",
+  ]
+}
+
 android_library("java") {
-  sources = [ "java/src/org/chromium/chrome/browser/safety_check/SafetyCheckSettingsFragment.java" ]
+  sources = [
+    "java/src/org/chromium/chrome/browser/safety_check/SafetyCheck.java",
+    "java/src/org/chromium/chrome/browser/safety_check/SafetyCheckBridge.java",
+    "java/src/org/chromium/chrome/browser/safety_check/SafetyCheckSettingsFragment.java",
+  ]
   deps = [
     ":java_resources",
+    "//base:base_java",
+    "//base:jni_java",
     "//third_party/android_deps:androidx_fragment_fragment_java",
     "//third_party/android_deps:androidx_preference_preference_java",
   ]
+  annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
+  srcjar_deps = [ ":safety_check_enums" ]
+}
+
+android_library("junit") {
+  # Skip platform checks since Robolectric depends on requires_android targets.
+  bypass_platform_checks = true
+  testonly = true
+  sources = [ "javatests/src/org/chromium/chrome/browser/safety_check/SafetyCheckBridgeTest.java" ]
+  deps = [
+    ":java",
+    "//base:base_java",
+    "//base:base_java_test_support",
+    "//base:base_junit_test_support",
+    "//base/test:test_support_java",
+    "//chrome/browser/preferences:java",
+    "//third_party/junit:junit",
+    "//third_party/mockito:mockito_java",
+  ]
 }
 
 android_resources("java_resources") {
   deps = [ "//chrome/browser/ui/android/strings:ui_strings_grd" ]
   custom_package = "org.chromium.chrome.browser.safety_check"
 }
+
+java_cpp_enum("safety_check_enums") {
+  sources = [ "//components/safety_check/safety_check.h" ]
+}
diff --git a/chrome/browser/safety_check/android/DEPS b/chrome/browser/safety_check/android/DEPS
new file mode 100644
index 0000000..6caefa6
--- /dev/null
+++ b/chrome/browser/safety_check/android/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+components/safety_check",
+  "+components/prefs",
+]
diff --git a/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheck.java b/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheck.java
new file mode 100644
index 0000000..9f69345
--- /dev/null
+++ b/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheck.java
@@ -0,0 +1,33 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.safety_check;
+
+import org.chromium.chrome.browser.safety_check.SafetyCheckBridge.SafetyCheckCommonObserver;
+
+/**
+ * Main class for all Safety check related logic.
+ */
+public class SafetyCheck implements SafetyCheckCommonObserver {
+    private SafetyCheckBridge mSafetyCheckBridge;
+
+    public SafetyCheck() {
+        mSafetyCheckBridge = new SafetyCheckBridge(SafetyCheck.this);
+    }
+
+    /**
+     * Triggers a Safe Browsing status check.
+     */
+    public void checkSafeBrowsing() {
+        mSafetyCheckBridge.checkSafeBrowsing();
+    }
+
+    /**
+     * Gets invoked once the Safe Browsing check is completed.
+     * @param status SafetyCheck::SafeBrowsingStatus enum value representing the Safe Browsing
+     *         state (see //components/safety_check/safety_check.h).
+     */
+    @Override
+    public void onSafeBrowsingCheckResult(@SafeBrowsingStatus int status) {}
+}
diff --git a/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckBridge.java b/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckBridge.java
new file mode 100644
index 0000000..f071c47
--- /dev/null
+++ b/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckBridge.java
@@ -0,0 +1,69 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.safety_check;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.NativeMethods;
+
+/**
+ * Provides access to the C++ multi-platform Safety check code in //components/safety_check.
+ */
+public class SafetyCheckBridge {
+    /**
+     * Observer for SafetyCheck code common to Desktop, Android, and iOS.
+     */
+    public interface SafetyCheckCommonObserver {
+        /**
+         * Gets invoked by the C++ code once the Safe Browsing check has results.
+         * @param status SafetyCheck::SafeBrowsingStatus enum value representing the Safe Browsing
+         *         state (see //components/safety_check/safety_check.h).
+         */
+        @CalledByNative("SafetyCheckCommonObserver")
+        void onSafeBrowsingCheckResult(@SafeBrowsingStatus int status);
+    }
+
+    /**
+     * Holds the C++ side of the Bridge class.
+     */
+    private long mNativeSafetyCheckBridge;
+
+    /**
+     * Initializes the C++ side.
+     * @param safetyCheckCommonObserver an observer instance that will receive the result of the
+     *  check using
+     *  {@link SafetyCheckCommonObserver#onSafeBrowsingCheckResult(SafeBrowsingStatus)}.
+     */
+    public SafetyCheckBridge(SafetyCheckCommonObserver safetyCheckCommonObserver) {
+        mNativeSafetyCheckBridge =
+                SafetyCheckBridgeJni.get().init(SafetyCheckBridge.this, safetyCheckCommonObserver);
+    }
+
+    /**
+     * Triggers the Safe Browsing check on the C++ side.
+     */
+    void checkSafeBrowsing() {
+        SafetyCheckBridgeJni.get().checkSafeBrowsing(
+                mNativeSafetyCheckBridge, SafetyCheckBridge.this);
+    }
+
+    /**
+     * Destroys the C++ side of the Bridge, freeing up all the associated memory.
+     */
+    void destroy() {
+        assert mNativeSafetyCheckBridge != 0;
+        SafetyCheckBridgeJni.get().destroy(mNativeSafetyCheckBridge, SafetyCheckBridge.this);
+        mNativeSafetyCheckBridge = 0;
+    }
+
+    /**
+     * C++ method signatures.
+     */
+    @NativeMethods
+    interface Natives {
+        long init(SafetyCheckBridge safetyCheckBridge, SafetyCheckCommonObserver observer);
+        void checkSafeBrowsing(long nativeSafetyCheckBridge, SafetyCheckBridge safetyCheckBridge);
+        void destroy(long nativeSafetyCheckBridge, SafetyCheckBridge safetyCheckBridge);
+    }
+}
diff --git a/chrome/browser/safety_check/android/javatests/src/org/chromium/chrome/browser/safety_check/SafetyCheckBridgeTest.java b/chrome/browser/safety_check/android/javatests/src/org/chromium/chrome/browser/safety_check/SafetyCheckBridgeTest.java
new file mode 100644
index 0000000..46c5ce9
--- /dev/null
+++ b/chrome/browser/safety_check/android/javatests/src/org/chromium/chrome/browser/safety_check/SafetyCheckBridgeTest.java
@@ -0,0 +1,78 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.safety_check;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.doAnswer;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.JniMocker;
+import org.chromium.chrome.browser.safety_check.SafetyCheckBridge.SafetyCheckCommonObserver;
+
+/** Unit tests for {@link SafetyCheckBridge}. */
+@RunWith(BaseRobolectricTestRunner.class)
+public class SafetyCheckBridgeTest {
+    class TestObserver implements SafetyCheckCommonObserver {
+        public boolean callbackInvoked = false;
+
+        private @SafeBrowsingStatus int mExpected = -1;
+
+        @Override
+        public void onSafeBrowsingCheckResult(@SafeBrowsingStatus int status) {
+            callbackInvoked = true;
+            assertEquals(mExpected, status);
+        }
+
+        public void setExpected(@SafeBrowsingStatus int expected) {
+            mExpected = expected;
+        }
+    }
+
+    @Rule
+    public JniMocker mocker = new JniMocker();
+    @Mock
+    private SafetyCheckBridge.Natives mNativeMock;
+
+    private SafetyCheckBridge mSafetyCheckBridge;
+    private TestObserver mObserver;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mocker.mock(SafetyCheckBridgeJni.TEST_HOOKS, mNativeMock);
+        mObserver = new TestObserver();
+        mSafetyCheckBridge = new SafetyCheckBridge(mObserver);
+    }
+
+    @Test
+    public void testCheckSafeBrowsing() {
+        assertFalse(mObserver.callbackInvoked);
+
+        @SafeBrowsingStatus
+        int expected = SafeBrowsingStatus.DISABLED_BY_ADMIN;
+        doAnswer(invocation -> {
+            mObserver.onSafeBrowsingCheckResult(expected);
+            return null;
+        })
+                .when(mNativeMock)
+                .checkSafeBrowsing(anyLong(), any(SafetyCheckBridge.class));
+        mObserver.setExpected(expected);
+
+        mSafetyCheckBridge.checkSafeBrowsing();
+
+        assertTrue(mObserver.callbackInvoked);
+    }
+}
\ No newline at end of file
diff --git a/chrome/browser/safety_check/android/safety_check_bridge.cc b/chrome/browser/safety_check/android/safety_check_bridge.cc
new file mode 100644
index 0000000..e2ef7ace
--- /dev/null
+++ b/chrome/browser/safety_check/android/safety_check_bridge.cc
@@ -0,0 +1,51 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/safety_check/android/safety_check_bridge.h"
+
+#include <jni.h>
+
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/safety_check/android/jni_headers/SafetyCheckBridge_jni.h"
+#include "components/safety_check/safety_check.h"
+
+static jlong JNI_SafetyCheckBridge_Init(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj,
+    const base::android::JavaParamRef<jobject>& j_safety_check_observer) {
+  return reinterpret_cast<intptr_t>(
+      new SafetyCheckBridge(env, j_safety_check_observer));
+}
+
+SafetyCheckBridge::SafetyCheckBridge(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& j_safety_check_observer)
+    : pref_service_(ProfileManager::GetActiveUserProfile()
+                        ->GetOriginalProfile()
+                        ->GetPrefs()),
+      j_safety_check_observer_(j_safety_check_observer) {
+  safety_check_.reset(new safety_check::SafetyCheck(this));
+}
+
+void SafetyCheckBridge::Destroy(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj) {
+  safety_check_.reset();
+  delete this;
+}
+
+void SafetyCheckBridge::CheckSafeBrowsing(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj) {
+  safety_check_->CheckSafeBrowsing(pref_service_);
+}
+
+void SafetyCheckBridge::OnSafeBrowsingCheckResult(
+    safety_check::SafetyCheck::SafeBrowsingStatus status) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_SafetyCheckCommonObserver_onSafeBrowsingCheckResult(
+      env, j_safety_check_observer_, static_cast<int>(status));
+}
+
+SafetyCheckBridge::~SafetyCheckBridge() = default;
diff --git a/chrome/browser/safety_check/android/safety_check_bridge.h b/chrome/browser/safety_check/android/safety_check_bridge.h
new file mode 100644
index 0000000..d657a1e
--- /dev/null
+++ b/chrome/browser/safety_check/android/safety_check_bridge.h
@@ -0,0 +1,46 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SAFETY_CHECK_ANDROID_SAFETY_CHECK_BRIDGE_H_
+#define CHROME_BROWSER_SAFETY_CHECK_ANDROID_SAFETY_CHECK_BRIDGE_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "components/prefs/pref_service.h"
+#include "components/safety_check/safety_check.h"
+
+// Allows the Java code to make use of cross-platform browser safety checks in
+// //components/safety_check.
+class SafetyCheckBridge
+    : public safety_check::SafetyCheck::SafetyCheckHandlerInterface {
+ public:
+  // Takes an observer object that will get invoked on check results.
+  SafetyCheckBridge(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& j_safety_check_observer);
+
+  // Destroys this bridge. Should only be invoked by the Java side.
+  void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+
+  // Checks the status of Safe Browsing and invokes |OnSafeBrowsingCheckResult|
+  // on the observer object with the result.
+  void CheckSafeBrowsing(JNIEnv* env,
+                         const base::android::JavaParamRef<jobject>& obj);
+
+  // Gets invoked by |safety_check::SafetyCheck| once the |SafeBrowsingStatus|
+  // is available. Invokes a method with the same name on the Java-side
+  // observer.
+  void OnSafeBrowsingCheckResult(
+      safety_check::SafetyCheck::SafeBrowsingStatus status) override;
+
+ private:
+  virtual ~SafetyCheckBridge();
+
+  PrefService* pref_service_ = nullptr;
+  std::unique_ptr<safety_check::SafetyCheck> safety_check_;
+  base::android::ScopedJavaGlobalRef<jobject> j_safety_check_observer_;
+};
+
+#endif  // CHROME_BROWSER_SAFETY_CHECK_ANDROID_SAFETY_CHECK_BRIDGE_H_
diff --git a/chrome/browser/search/search_unittest.cc b/chrome/browser/search/search_unittest.cc
index 2cdfba1..a921ac1 100644
--- a/chrome/browser/search/search_unittest.cc
+++ b/chrome/browser/search/search_unittest.cc
@@ -29,6 +29,7 @@
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_utils.h"
 #include "url/gurl.h"
 
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
@@ -162,21 +163,27 @@
   const char* end_url;
   bool end_in_instant_process;
   bool same_site_instance;
+  bool same_process;
 } kProcessIsolationTestCases[] = {
     {"Local NTP -> SRP", "chrome-search://local-ntp", true,
-     "https://foo.com/url", false, false},
+     "https://foo.com/url", false, false, false},
     {"Local NTP -> Regular", "chrome-search://local-ntp", true,
-     "https://foo.com/other", false, false},
+     "https://foo.com/other", false, false, false},
     {"Remote NTP -> SRP", "https://foo.com/newtab", true, "https://foo.com/url",
-     false, false},
+     false, false, false},
     {"Remote NTP -> Regular", "https://foo.com/newtab", true,
-     "https://foo.com/other", false, false},
+     "https://foo.com/other", false, false, false},
     {"SRP -> SRP", "https://foo.com/url", false, "https://foo.com/url", false,
-     true},
+     true, true},
+    // Same-site (but not same URL) navigations might switch site instances but
+    // keep the same process when ProactivelySwapBrowsingInstance is enabled on
+    // same-site navigations.
     {"SRP -> Regular", "https://foo.com/url", false, "https://foo.com/other",
-     false, true},
+     false, !content::CanSameSiteMainFrameNavigationsChangeSiteInstances(),
+     true},
     {"Regular -> SRP", "https://foo.com/other", false, "https://foo.com/url",
-     false, true},
+     false, !content::CanSameSiteMainFrameNavigationsChangeSiteInstances(),
+     true},
 };
 
 TEST_F(SearchTest, ProcessIsolation) {
@@ -210,7 +217,7 @@
     EXPECT_EQ(test.same_site_instance,
               start_rvh == contents->GetRenderViewHost())
         << test.description;
-    EXPECT_EQ(test.same_site_instance,
+    EXPECT_EQ(test.same_process,
               start_rph == contents->GetMainFrame()->GetProcess())
         << test.description;
   }
@@ -249,7 +256,7 @@
     EXPECT_EQ(test.same_site_instance,
               start_rvh == contents->GetRenderViewHost())
         << test.description;
-    EXPECT_EQ(test.same_site_instance,
+    EXPECT_EQ(test.same_process,
               start_rph == contents->GetMainFrame()->GetProcess())
         << test.description;
   }
diff --git a/chrome/browser/sharing/sharing_message_model_type_controller.cc b/chrome/browser/sharing/sharing_message_model_type_controller.cc
index f6d4ac65..9b2a352 100644
--- a/chrome/browser/sharing/sharing_message_model_type_controller.cc
+++ b/chrome/browser/sharing/sharing_message_model_type_controller.cc
@@ -33,9 +33,13 @@
 syncer::DataTypeController::PreconditionState
 SharingMessageModelTypeController::GetPreconditionState() const {
   DCHECK(CalledOnValidThread());
-  return syncer::IsWebSignout(sync_service_->GetAuthError())
-             ? PreconditionState::kMustStopAndClearData
-             : PreconditionState::kPreconditionsMet;
+  if (syncer::IsWebSignout(sync_service_->GetAuthError())) {
+    return PreconditionState::kMustStopAndClearData;
+  }
+  if (sync_service_->GetBackedOffDataTypes().Has(syncer::SHARING_MESSAGE)) {
+    return PreconditionState::kMustStopAndClearData;
+  }
+  return PreconditionState::kPreconditionsMet;
 }
 
 void SharingMessageModelTypeController::OnStateChanged(
diff --git a/chrome/browser/ssl/security_state_tab_helper_browsertest.cc b/chrome/browser/ssl/security_state_tab_helper_browsertest.cc
index 958793e..9e366ae 100644
--- a/chrome/browser/ssl/security_state_tab_helper_browsertest.cc
+++ b/chrome/browser/ssl/security_state_tab_helper_browsertest.cc
@@ -1809,9 +1809,8 @@
 
 // Visit a valid HTTPS page, then a broken HTTPS page, and then go back,
 // and test that the observed security style matches.
-// TODO(https://crbug.com/638576) disabled due to flakiness.
 IN_PROC_BROWSER_TEST_F(DidChangeVisibleSecurityStateTest,
-                       DISABLED_DidChangeVisibleSecurityStateObserverGoBack) {
+                       DidChangeVisibleSecurityStateObserverGoBack) {
   ASSERT_TRUE(https_server_.Start());
 
   net::EmbeddedTestServer https_test_server_expired(
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index 9bfca39..88fc170 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -1122,6 +1122,37 @@
       tab, net::CERT_STATUS_DATE_INVALID, AuthState::RAN_INSECURE_CONTENT);
 }
 
+// Tests that when a subframe commits a main resource with a certificate error,
+// the navigation entry is marked as insecure.
+IN_PROC_BROWSER_TEST_F(SSLUITestIgnoreCertErrors, SubframeHasCertError) {
+  ASSERT_TRUE(https_server_mismatched_.Start());
+  // Load a page with a data: favicon URL to suppress a favicon request. A
+  // favicon request can cause the navigation entry to get marked as having run
+  // insecure content (favicons are treated as active content), which would
+  // interfere with the test expectation below.
+  GURL main_frame_url =
+      https_server_mismatched_.GetURL("a.test", "/data_favicon.html");
+  EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), main_frame_url));
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_TRUE(tab);
+  EXPECT_FALSE(
+      tab->GetController().GetLastCommittedEntry()->GetSSL().content_status &
+      content::SSLStatus::RAN_CONTENT_WITH_CERT_ERRORS);
+
+  GURL subframe_url =
+      https_server_mismatched_.GetURL("b.test", "/data_favicon.html");
+  content::TestNavigationObserver iframe_observer(tab);
+  EXPECT_TRUE(content::ExecJs(
+      tab, content::JsReplace("var i = document.createElement('iframe');"
+                              "i.src = $1;"
+                              "document.body.appendChild(i);",
+                              subframe_url.spec())));
+  iframe_observer.Wait();
+  EXPECT_TRUE(
+      tab->GetController().GetLastCommittedEntry()->GetSSL().content_status &
+      content::SSLStatus::RAN_CONTENT_WITH_CERT_ERRORS);
+}
+
 namespace {
 
 // A WebContentsObserver that allows the user to wait for a same-document
diff --git a/chrome/browser/sync/test/integration/single_client_sharing_message_sync_test.cc b/chrome/browser/sync/test/integration/single_client_sharing_message_sync_test.cc
index 5e01b7c..0316c80 100644
--- a/chrome/browser/sync/test/integration/single_client_sharing_message_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_sharing_message_sync_test.cc
@@ -43,6 +43,16 @@
   base::Time last_synced_time_;
 };
 
+class BackedOffSharingMessageChecker : public SingleClientStatusChangeChecker {
+ public:
+  explicit BackedOffSharingMessageChecker(syncer::ProfileSyncService* service)
+      : SingleClientStatusChangeChecker(service) {}
+
+  bool IsExitConditionSatisfied(std::ostream* os) override {
+    return service()->GetBackedOffDataTypes().Has(syncer::SHARING_MESSAGE);
+  }
+};
+
 class SharingMessageEqualityChecker : public SingleClientStatusChangeChecker {
  public:
   SharingMessageEqualityChecker(
@@ -183,6 +193,39 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SingleClientSharingMessageSyncTest,
+                       ShouldStopDataTypeWhenBackedOff) {
+  base::MockRepeatingCallback<void(const sync_pb::SharingMessageCommitError&)>
+      callback;
+
+  ASSERT_TRUE(SetupSync());
+  SharingMessageBridge* sharing_message_bridge =
+      SharingMessageBridgeFactory::GetForBrowserContext(GetProfile(0));
+  SharingMessageSpecifics specifics;
+  specifics.set_payload("payload");
+  sharing_message_bridge->SendSharingMessage(
+      std::make_unique<SharingMessageSpecifics>(specifics), callback.Get());
+
+  EXPECT_CALL(
+      callback,
+      Run(HasErrorCode(sync_pb::SharingMessageCommitError::SYNC_TURNED_OFF)));
+  ASSERT_FALSE(
+      GetSyncService(0)->GetBackedOffDataTypes().Has(syncer::SHARING_MESSAGE));
+
+  // Run the data type into backed off state before the message gets sent.
+  fake_server::FakeServerHttpPostProvider::DisableNetwork();
+
+  ASSERT_TRUE(BackedOffSharingMessageChecker(GetSyncService(0)).Wait());
+
+  EXPECT_TRUE(
+      GetSyncService(0)->GetBackedOffDataTypes().Has(syncer::SHARING_MESSAGE));
+  EXPECT_CALL(
+      callback,
+      Run(HasErrorCode(sync_pb::SharingMessageCommitError::SYNC_TURNED_OFF)));
+  sharing_message_bridge->SendSharingMessage(
+      std::make_unique<SharingMessageSpecifics>(specifics), callback.Get());
+}
+
+IN_PROC_BROWSER_TEST_F(SingleClientSharingMessageSyncTest,
                        ShouldCleanPendingMessagesAfterSyncPaused) {
   base::MockOnceCallback<void(const sync_pb::SharingMessageCommitError&)>
       callback;
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
index abf173e..de92a5d 100644
--- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
@@ -90,4 +90,13 @@
     protected boolean isCustomTab() {
         return false;
     }
+
+    /**
+     * Checks if the associated tab is running an activity for installed webapp (TWA only for now),
+     * and whether the geolocation request should be delegated to the client app.
+     * @return true if this is TWA and should delegate geolocation request.
+     */
+    protected boolean isInstalledWebappDelegateGeolocation() {
+        return false;
+    }
 }
diff --git a/chrome/browser/themes/browser_theme_pack.h b/chrome/browser/themes/browser_theme_pack.h
index 79622c2e..24db72ac 100644
--- a/chrome/browser/themes/browser_theme_pack.h
+++ b/chrome/browser/themes/browser_theme_pack.h
@@ -301,7 +301,8 @@
 
     // theme_id without NULL terminator.
     uint8_t theme_id[16];
-  }* header_ = nullptr;
+  };
+  BrowserThemePackHeader* header_ = nullptr;
 
   // The remaining structs represent individual entries in an array. For the
   // following three structs, BrowserThemePack will either allocate an array or
@@ -311,17 +312,20 @@
     double h;
     double s;
     double l;
-  }* tints_ = nullptr;
+  };
+  TintEntry* tints_ = nullptr;
 
   struct ColorPair {
     int32_t id;
     SkColor color;
-  }* colors_ = nullptr;
+  };
+  ColorPair* colors_ = nullptr;
 
   struct DisplayPropertyPair {
     int32_t id;
     int32_t property;
-  }* display_properties_ = nullptr;
+  };
+  DisplayPropertyPair* display_properties_ = nullptr;
 
   // A list of included source images. A pointer to a -1 terminated array of
   // our persistent IDs.
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 87a50bd..f51cf634 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -3215,10 +3215,6 @@
         Reopen Chrome.
       </message>
 
-      <if expr="enable_vr">
-        <part file="xr_consent_ui_strings_java.grdp" />
-      </if>
-
       <if expr="enable_arcore">
         <!-- ARCore check infobar -->
         <message name="IDS_AR_CORE_CHECK_INFOBAR_INSTALL_TEXT" desc="Text to be displayed in the ARCore check infobar. When a WebXR page is loaded, if ARCore is needed to display AR content and it is not installed, an infobar will be shown to the user prompting them to install ARCore.">
@@ -3232,19 +3228,6 @@
         <message name="IDS_AR_MODULE_TITLE" desc="Text shown when the AR module is referenced in install start, success, failure UI (e.g. in IDS_MODULE_INSTALL_START_TEXT, which will expand to 'Installing Augmented Reality for Chrome…').">
           Augmented Reality
         </message>
-        <message name="IDS_AR_IMMERSIVE_MODE_CONSENT_TITLE" desc="Title for dialog shown when a site requests consent for starting an augmented reality session.">
-          Enter AR from <ph name="DOMAIN">%s<ex>example.com</ex></ph>?
-        </message>
-        <message name="IDS_AR_IMMERSIVE_MODE_CONSENT_MESSAGE" desc="Message for dialog shown when a site requests consent for starting an augmented reality session.">
-          While you're in AR, this site may be able to:
-• create a 3D map of your environment
-• track camera motion
-
-Only you can see what your camera is looking at. The site can't see your camera's images.
-        </message>
-        <message name="IDS_AR_IMMERSIVE_MODE_CONSENT_BUTTON" desc="Confirm button for dialog shown when a site requests consent for starting an augmented reality session.">
-          Enter AR
-        </message>
 
         <!-- App upgrade from Play Store -->
         <message name="IDS_UPDATE_FROM_MARKET" desc="Title of button that will direct the user to update an app from the market (Play Store)">
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_AR_IMMERSIVE_MODE_CONSENT_BUTTON.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_AR_IMMERSIVE_MODE_CONSENT_BUTTON.png.sha1
deleted file mode 100644
index b60140d..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_AR_IMMERSIVE_MODE_CONSENT_BUTTON.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-45a159c60efc8bf926c8e89787ff9212bfffb83c
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_AR_IMMERSIVE_MODE_CONSENT_MESSAGE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_AR_IMMERSIVE_MODE_CONSENT_MESSAGE.png.sha1
deleted file mode 100644
index 478445c7..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_AR_IMMERSIVE_MODE_CONSENT_MESSAGE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-caf897ed2839d89787145a0acb75b02b117e9d66
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_AR_IMMERSIVE_MODE_CONSENT_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_AR_IMMERSIVE_MODE_CONSENT_TITLE.png.sha1
deleted file mode 100644
index efdc3b2..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_AR_IMMERSIVE_MODE_CONSENT_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-2f474dc661b55506e97299a4c4012b56f59aa6a8
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_mk.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_mk.xtb
index 735c5c58..77f841f 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_mk.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_mk.xtb
@@ -436,7 +436,7 @@
 <translation id="4634124774493850572">Употреби ја лозинката</translation>
 <translation id="4650364565596261010">Стандардна поставка за системот</translation>
 <translation id="4660838440047236328">распоредот на вашата соба</translation>
-<translation id="4662373422909645029">Прекар не може да има бројки</translation>
+<translation id="4662373422909645029">Прекарот не може да содржи броеви</translation>
 <translation id="4663756553811254707"><ph name="NUMBER_OF_BOOKMARKS" /> обележувачи се избришани</translation>
 <translation id="4665282149850138822"><ph name="NAME" /> е додадена на вашиот Почетен екран</translation>
 <translation id="4684427112815847243">Синхронизирај сѐ</translation>
diff --git a/chrome/browser/ui/android/strings/xr_consent_ui_strings_java.grdp b/chrome/browser/ui/android/strings/xr_consent_ui_strings_java.grdp
deleted file mode 100644
index 5ff87217..0000000
--- a/chrome/browser/ui/android/strings/xr_consent_ui_strings_java.grdp
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2019 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-<!-- XR specific strings (included from generated_resources.grd and android_chrome_strings.grd). -->
-<!-- These strings are used in the consent flow dialog. -->
-<grit-part>
-  <!-- XR consent dialog. -->
-  <message name="IDS_XR_CONSENT_DIALOG_TITLE" desc="Title of the user consent dialog displayed before allowing a website to start a VR presentation">
-    Enter VR from <ph name="DOMAIN">%s<ex>example.com</ex></ph>?
-  </message>
-  <message name="IDS_XR_CONSENT_DIALOG_DESCRIPTION_DEFAULT" desc="This is the header for a bulleted list of potential concerns that we want to ensure the user is aware of before entering VR. This header and the appended items of the bulleted list make up the body of the user consent dialog displayed before a website may start a VR presentation.">
-    While you're in VR, this site may be able to learn about:
-  </message>
-  <message name="IDS_XR_CONSENT_BULLET" desc="Unicode bullet for list items. Similar to IDS_LIST_BULLET from desktop generated_resources">
-    •  <ph name="LIST_ITEM_TEXT">%s<ex>the layout of your room</ex></ph>
-  </message>
-  <message name="IDS_XR_CONSENT_DIALOG_DESCRIPTION_PHYSICAL_FEATURES" desc="Item for the bulleted list of potential concerns in the consent dialog indicating that physical features may be exposed.">
-    your physical features, such as height
-  </message>
-  <message name="IDS_XR_CONSENT_DIALOG_DESCRIPTION_FLOOR_PLAN" desc="Item for the bulleted list of potential concerns in the consent dialog indicating that phyiscal features may be exposed.">
-    the layout of your room
-  </message>
-  <message name="IDS_XR_CONSENT_DIALOG_BUTTON_ALLOW_AND_ENTER_VR" desc="Text on the button of a user consent dialog which allows a website to start a VR presentation">
-    Enter VR
-  </message>
-</grit-part>
diff --git a/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_BUTTON_ALLOW_AND_ENTER_VR.png.sha1 b/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_BUTTON_ALLOW_AND_ENTER_VR.png.sha1
deleted file mode 100644
index b76fdbd8..0000000
--- a/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_BUTTON_ALLOW_AND_ENTER_VR.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-260a6d63d0676961a5095e1e4640ca6eeeca4080
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_BUTTON_DENY_VR.png.sha1 b/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_BUTTON_DENY_VR.png.sha1
deleted file mode 100644
index f7f6408..0000000
--- a/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_BUTTON_DENY_VR.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-91e04b62280221cdc2d4f2c58c555ba819945495
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_DEFAULT.png.sha1 b/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_DEFAULT.png.sha1
deleted file mode 100644
index 958eed97..0000000
--- a/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_DEFAULT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-a3645ec49c52139e87dfe4546f81106ae4758378
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_FLOOR_PLAN.png.sha1 b/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_FLOOR_PLAN.png.sha1
deleted file mode 100644
index 556ce6d..0000000
--- a/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_FLOOR_PLAN.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-097b4f4691849812b1373d6a1662615f7946fe7a
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_PHYSICAL_FEATURES.png.sha1 b/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_PHYSICAL_FEATURES.png.sha1
deleted file mode 100644
index fe38d8a..0000000
--- a/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_DESCRIPTION_PHYSICAL_FEATURES.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-8cb47ed5d5b6f9a417296d27786aa37385761182
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_TITLE.png.sha1 b/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_TITLE.png.sha1
deleted file mode 100644
index f020169..0000000
--- a/chrome/browser/ui/android/strings/xr_consent_ui_strings_java_grdp/IDS_XR_CONSENT_DIALOG_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-e5af6dcbda415543160df6950bd986a50a48ae46
\ No newline at end of file
diff --git a/chrome/browser/ui/app_list/app_list_test_util.cc b/chrome/browser/ui/app_list/app_list_test_util.cc
index 2e8d005..7534fa3 100644
--- a/chrome/browser/ui/app_list/app_list_test_util.cc
+++ b/chrome/browser/ui/app_list/app_list_test_util.cc
@@ -4,9 +4,16 @@
 
 #include "chrome/browser/ui/app_list/app_list_test_util.h"
 
+#include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/web_applications/pending_app_manager_impl.h"
+#include "chrome/browser/web_applications/test/test_system_web_app_manager.h"
+#include "chrome/browser/web_applications/test/test_web_app_provider.h"
+#include "chrome/browser/web_applications/test/test_web_app_url_loader.h"
 #include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_features.h"
+#include "chrome/test/base/testing_profile.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension_set.h"
 
@@ -37,9 +44,32 @@
   InitializeInstalledExtensionService(pref_path, source_install_dir);
   service_->Init();
 
+  if (base::FeatureList::IsEnabled(features::kDesktopPWAsWithoutExtensions))
+    ConfigureWebAppProvider();
+
   // Let any async services complete their set-up.
   base::RunLoop().RunUntilIdle();
 
   // There should be 4 extensions in the test profile.
   ASSERT_EQ(4U, registry()->enabled_extensions().size());
 }
+
+void AppListTestBase::ConfigureWebAppProvider() {
+  Profile* const profile = testing_profile();
+
+  auto url_loader = std::make_unique<web_app::TestWebAppUrlLoader>();
+  url_loader_ = url_loader.get();
+
+  auto pending_app_manager =
+      std::make_unique<web_app::PendingAppManagerImpl>(profile);
+  pending_app_manager->SetUrlLoaderForTesting(std::move(url_loader));
+
+  auto system_web_app_manager =
+      std::make_unique<web_app::TestSystemWebAppManager>(profile);
+
+  auto* const provider = web_app::TestWebAppProvider::Get(profile);
+  provider->SetPendingAppManager(std::move(pending_app_manager));
+  provider->SetSystemWebAppManager(std::move(system_web_app_manager));
+  provider->SetRunSubsystemStartupTasks(true);
+  provider->Start();
+}
diff --git a/chrome/browser/ui/app_list/app_list_test_util.h b/chrome/browser/ui/app_list/app_list_test_util.h
index f47c273..5f31548 100644
--- a/chrome/browser/ui/app_list/app_list_test_util.h
+++ b/chrome/browser/ui/app_list/app_list_test_util.h
@@ -7,6 +7,10 @@
 
 #include "chrome/browser/extensions/extension_service_test_base.h"
 
+namespace web_app {
+class TestWebAppUrlLoader;
+}  // namespace web_app
+
 // Base class for app list unit tests that use the "app_list" test profile.
 class AppListTestBase : public extensions::ExtensionServiceTestBase {
  public:
@@ -18,6 +22,13 @@
   ~AppListTestBase() override;
 
   void SetUp() override;
+
+  web_app::TestWebAppUrlLoader& url_loader() { return *url_loader_; }
+
+ private:
+  void ConfigureWebAppProvider();
+
+  web_app::TestWebAppUrlLoader* url_loader_ = nullptr;
 };
 
 #endif  // CHROME_BROWSER_UI_APP_LIST_APP_LIST_TEST_UTIL_H_
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc b/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc
index 7c873df7..7f560d2 100644
--- a/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc
+++ b/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/files/file_path.h"
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/values.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
@@ -32,9 +33,12 @@
 #include "chrome/browser/ui/app_list/internal_app/internal_app_metadata.h"
 #include "chrome/browser/ui/app_list/test/fake_app_list_model_updater.h"
 #include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
+#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
 #include "chrome/browser/web_applications/test/test_web_app_provider.h"
 #include "chrome/browser/web_applications/test/web_app_test.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/chrome_features.h"
+#include "chrome/common/web_application_info.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -154,11 +158,6 @@
   AppServiceAppModelBuilderTest& operator=(
       const AppServiceAppModelBuilderTest&) = delete;
 
-  void SetUp() override {
-    AppListTestBase::SetUp();
-    web_app::TestWebAppProvider::Get(testing_profile())->Start();
-  }
-
   void TearDown() override {
     ResetBuilder();
     AppListTestBase::TearDown();
@@ -204,7 +203,7 @@
 class ExtensionAppTest : public AppServiceAppModelBuilderTest {
  public:
   void SetUp() override {
-    AppListTestBase::SetUp();
+    AppServiceAppModelBuilderTest::SetUp();
 
     default_apps_ = {"Hosted App", "Packaged App 1", "Packaged App 2"};
     CreateBuilder();
@@ -221,6 +220,31 @@
   std::vector<std::string> default_apps_;
 };
 
+using BookmarkAppBuilderTest = ExtensionAppTest;
+
+class WebAppBuilderTest : public AppServiceAppModelBuilderTest {
+ public:
+  void SetUp() override {
+    AppServiceAppModelBuilderTest::SetUp();
+
+    base::RunLoop run_loop;
+    web_app::WebAppProvider::Get(testing_profile())
+        ->on_registry_ready()
+        .Post(FROM_HERE, run_loop.QuitClosure());
+    run_loop.Run();
+
+    CreateBuilder();
+  }
+
+ protected:
+  // Creates a new builder, destroying any existing one.
+  void CreateBuilder() {
+    AppServiceAppModelBuilderTest::CreateBuilder(false /*guest_mode*/);
+    RemoveApps(apps::mojom::AppType::kWeb, testing_profile(),
+               model_updater_.get());
+  }
+};
+
 TEST_P(BuiltInAppTest, Build) {
   // The internal apps list is provided by GetInternalAppList() in
   // internal_app_metadata.cc. Only count the apps can display in launcher.
@@ -411,7 +435,7 @@
 }
 
 // This test adds a bookmark app to the app list.
-TEST_P(ExtensionAppTest, BookmarkApp) {
+TEST_P(BookmarkAppBuilderTest, BookmarkAppList) {
   const std::string kAppName = "Bookmark App";
   const std::string kAppVersion = "2014.1.24.19748";
   const std::string kAppUrl = "http://google.com";
@@ -437,6 +461,29 @@
             GetModelContent(model_updater_.get()));
 }
 
+// This test adds a web app to the app list.
+TEST_P(WebAppBuilderTest, WebAppList) {
+  Profile* const profile = profile_.get();
+
+  const std::string kAppName = "Web App";
+  const GURL kAppUrl("https://example.com/");
+
+  auto web_app_info = std::make_unique<WebApplicationInfo>();
+  web_app_info->title = base::UTF8ToUTF16(kAppName);
+  web_app_info->app_url = kAppUrl;
+  web_app_info->scope = kAppUrl;
+  web_app_info->open_as_window = true;
+
+  const web_app::AppId app_id =
+      web_app::InstallWebApp(profile, std::move(web_app_info));
+
+  app_service_test_.SetUp(profile_.get());
+  RemoveApps(apps::mojom::AppType::kWeb, profile, model_updater_.get());
+  EXPECT_EQ(1u, model_updater_->ItemCount());
+  EXPECT_EQ((std::vector<std::string>{kAppName}),
+            GetModelContent(model_updater_.get()));
+}
+
 class CrostiniAppTest : public AppServiceAppModelBuilderTest {
  public:
   CrostiniAppTest() {
@@ -773,10 +820,21 @@
 
 INSTANTIATE_TEST_SUITE_P(All,
                          ExtensionAppTest,
+                         ::testing::Values(ProviderType::kBookmarkApps,
+                                           ProviderType::kWebApps),
+                         web_app::ProviderTypeParamToString);
+
+INSTANTIATE_TEST_SUITE_P(All,
+                         BookmarkAppBuilderTest,
                          ::testing::Values(ProviderType::kBookmarkApps),
                          web_app::ProviderTypeParamToString);
 
 INSTANTIATE_TEST_SUITE_P(All,
+                         WebAppBuilderTest,
+                         ::testing::Values(ProviderType::kWebApps),
+                         web_app::ProviderTypeParamToString);
+
+INSTANTIATE_TEST_SUITE_P(All,
                          CrostiniAppTest,
                          ::testing::Values(ProviderType::kBookmarkApps,
                                            ProviderType::kWebApps),
diff --git a/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc
index 92446106..b6b79dd 100644
--- a/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc
@@ -34,7 +34,6 @@
 #include "chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h"
 #include "chrome/browser/ui/app_list/test/fake_app_list_model_updater.h"
 #include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
-#include "chrome/browser/web_applications/test/test_web_app_provider.h"
 #include "chrome/browser/web_applications/test/web_app_test.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_features.h"
@@ -725,7 +724,6 @@
   EXPECT_EQ("", RunQuery("linux"));
 
   // This both allows Crostini UI and enables Crostini.
-  web_app::TestWebAppProvider::Get(testing_profile())->Start();
   crostini::CrostiniTestHelper crostini_test_helper(testing_profile());
   crostini_test_helper.ReInitializeAppServiceIntegration();
   CreateSearch();
@@ -753,7 +751,6 @@
 
 TEST_P(AppSearchProviderCrostiniTest, CrostiniApp) {
   // This both allows Crostini UI and enables Crostini.
-  web_app::TestWebAppProvider::Get(testing_profile())->Start();
   crostini::CrostiniTestHelper crostini_test_helper(testing_profile());
   crostini_test_helper.ReInitializeAppServiceIntegration();
   CreateSearch();
diff --git a/chrome/browser/ui/extensions/settings_overridden_params_providers_browsertest.cc b/chrome/browser/ui/extensions/settings_overridden_params_providers_browsertest.cc
index 43b4fb1..40ceed5 100644
--- a/chrome/browser/ui/extensions/settings_overridden_params_providers_browsertest.cc
+++ b/chrome/browser/ui/extensions/settings_overridden_params_providers_browsertest.cc
@@ -114,7 +114,7 @@
 
   // Validate the body message, since it has a bit of formatting applied.
   EXPECT_EQ(
-      "The Search Override Extension extension changed search to use "
+      "The \"Search Override Extension\" extension changed search to use "
       "example.com",
       base::UTF16ToUTF8(params->dialog_message));
 }
diff --git a/chrome/browser/ui/find_bar/find_backend_unittest.cc b/chrome/browser/ui/find_bar/find_backend_unittest.cc
index 810c1da..94dc660 100644
--- a/chrome/browser/ui/find_bar/find_backend_unittest.cc
+++ b/chrome/browser/ui/find_bar/find_backend_unittest.cc
@@ -61,9 +61,10 @@
   base::string16 search_term2 = base::ASCIIToUTF16(" but the economy ");
   base::string16 search_term3 = base::ASCIIToUTF16(" eated it.       ");
 
-  // Start searching in the first WebContents, searching forwards but not case
-  // sensitive (as indicated by the last two params).
-  find_tab_helper->StartFinding(search_term1, true, false);
+  // Start searching in the first WebContents.
+  find_tab_helper->StartFinding(search_term1, true /* forward_direction */,
+                                false /* case_sensitive */,
+                                true /* find_next_if_selection_matches */);
 
   // Pre-populate string should always match between the two, but find_text
   // should not.
@@ -72,9 +73,10 @@
   EXPECT_EQ(search_term1, FindPrepopulateText(contents2.get()));
   EXPECT_EQ(base::string16(), find_tab_helper2->find_text());
 
-  // Now search in the other WebContents, searching forwards but not case
-  // sensitive (as indicated by the last two params).
-  find_tab_helper2->StartFinding(search_term2, true, false);
+  // Now search in the other WebContents.
+  find_tab_helper2->StartFinding(search_term2, true /* forward_direction */,
+                                 false /* case_sensitive */,
+                                 true /* find_next_if_selection_matches */);
 
   // Again, pre-populate string should always match between the two, but
   // find_text should not.
@@ -83,9 +85,10 @@
   EXPECT_EQ(search_term2, FindPrepopulateText(contents2.get()));
   EXPECT_EQ(search_term2, find_tab_helper2->find_text());
 
-  // Search again in the first WebContents, searching forwards but not case
-  // find_tab_helper (as indicated by the last two params).
-  find_tab_helper->StartFinding(search_term3, true, false);
+  // Search again in the first WebContents
+  find_tab_helper->StartFinding(search_term3, true /* forward_direction */,
+                                false /* case_sensitive */,
+                                true /* find_next_if_selection_matches */);
 
   // The fallback search term for the first WebContents will be the original
   // search.
diff --git a/chrome/browser/ui/find_bar/find_bar_controller.cc b/chrome/browser/ui/find_bar/find_bar_controller.cc
index 716b729..ba997812 100644
--- a/chrome/browser/ui/find_bar/find_bar_controller.cc
+++ b/chrome/browser/ui/find_bar/find_bar_controller.cc
@@ -50,38 +50,36 @@
   }
   find_bar_->SetFocusAndSelection();
 
-  base::string16 find_text;
+  if (find_next) {
+    base::string16 find_text;
 
 #if defined(OS_MACOSX)
-  if (find_next) {
-    // For macOS, we always want to search for the current contents of the find
-    // bar on OS X, rather than the behavior we'd get with empty find_text
-    // (see FindBarState::GetSearchPrepopulateText).
+    // For macOS, we always want to search for the current contents of the
+    // find bar on OS X, rather than the behavior we'd get with empty
+    // find_text (see FindBarState::GetSearchPrepopulateText).
     find_text = find_bar_->GetFindText();
-  }
 #endif
 
-  if (!find_next && !has_user_modified_text_) {
+    find_tab_helper->StartFinding(find_text, forward_direction,
+                                  false /* case_sensitive */,
+                                  true /* find_next_if_selection_matches */);
+    return;
+  }
+
+  if (!has_user_modified_text_) {
     base::string16 selected_text = GetSelectedText();
     auto selected_length = selected_text.length();
     if (selected_length > 0 && selected_length <= 250) {
-      find_text = selected_text;
-      find_bar_->SetFindTextAndSelectedRange(find_text,
-                                             gfx::Range(0, find_text.length()));
-      if (web_contents_) {
-        // Collapse the selection to its start, so we can run a find_next and
-        // make it find the selection. This is a no-op in terms of what ends
-        // up selected, but initializes the rest of the find machinery (like
-        // showing how many matches there are in the document).
-        web_contents_->AdjustSelectionByCharacterOffset(0, -selected_length,
-                                                        false);
-        find_next = true;
-      }
+      find_bar_->SetFindTextAndSelectedRange(
+          selected_text, gfx::Range(0, selected_text.length()));
+      // Start a new find based on the selection.
+      // |find_next_if_selection_matches| is set to false so that the initial
+      // result will be the selection itself.
+      find_tab_helper->StartFinding(selected_text, true /* forward_direction */,
+                                    false /* case_sensitive */,
+                                    false /* find_next_if_selection_matches */);
     }
   }
-
-  if (find_next)
-    find_tab_helper->StartFinding(find_text, forward_direction, false);
 }
 
 void FindBarController::EndFindSession(
diff --git a/chrome/browser/ui/signin_reauth_view_controller_browsertest.cc b/chrome/browser/ui/signin_reauth_view_controller_browsertest.cc
index d08a420..eb09f93c 100644
--- a/chrome/browser/ui/signin_reauth_view_controller_browsertest.cc
+++ b/chrome/browser/ui/signin_reauth_view_controller_browsertest.cc
@@ -27,6 +27,7 @@
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
+#include "content/public/test/test_utils.h"
 #include "google_apis/gaia/core_account_id.h"
 #include "google_apis/gaia/gaia_switches.h"
 #include "net/base/escape.h"
@@ -110,11 +111,14 @@
   }
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
+    // HTTPS server only serves a valid cert for localhost, so this is needed to
+    // load pages from other hosts without an interstitial.
+    command_line->AppendSwitch("ignore-certificate-errors");
     command_line->AppendSwitchASCII(switches::kGaiaUrl, base_url().spec());
   }
 
   void SetUpOnMainThread() override {
-    InProcessBrowserTest::SetUpOnMainThread();
+    host_resolver()->AddRule("*", "127.0.0.1");
 
     https_server()->ServeFilesFromSourceDirectory("chrome/test/data");
     https_server()->RegisterRequestHandler(
@@ -129,6 +133,7 @@
                       .account_id;
 
     reauth_result_loop_ = std::make_unique<base::RunLoop>();
+    InProcessBrowserTest::SetUpOnMainThread();
   }
 
   void ShowReauthPrompt() {
@@ -260,7 +265,7 @@
   content::WebContents* original_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
 
-  const GURL& target_url = https_server()->GetURL("/link_with_target.html");
+  const GURL target_url = https_server()->GetURL("/link_with_target.html");
   content::TestNavigationObserver target_content_observer(target_url);
   target_content_observer.StartWatchingNewWebContents();
   ShowReauthPrompt();
@@ -286,3 +291,60 @@
   EXPECT_NE(new_contents, dialog_contents);
   EXPECT_EQ(new_contents->GetURL(), https_server()->GetURL("/title1.html"));
 }
+
+// Tests that the authentication flow that goes outside of the reauth host is
+// shown in a new tab.
+IN_PROC_BROWSER_TEST_F(SigninReauthViewControllerBrowserTest,
+                       CompleteSAMLInNewTab) {
+  content::WebContents* original_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  // The URL contains a link that navigates to the reauth success URL.
+  const std::string target_path = net::test_server::GetFilePathWithReplacements(
+      "/signin/link_with_replacements.html",
+      {{"REPLACE_WITH_URL", https_server()->GetURL(kReauthDonePath).spec()}});
+  const GURL target_url =
+      https_server()->GetURL("3p-identity-provider.com", target_path);
+
+  content::TestNavigationObserver target_content_observer(target_url);
+  target_content_observer.StartWatchingNewWebContents();
+  ShowReauthPrompt();
+  RedirectGaiaChallengeTo(target_url);
+
+  ui_test_utils::TabAddedWaiter tab_added_waiter(browser());
+  ReauthTestObserver reauth_observer(signin_reauth_view_controller());
+  ASSERT_TRUE(login_ui_test_utils::ConfirmReauthConfirmationDialog(
+      browser(), kReauthDialogTimeout));
+  reauth_observer.WaitUntilGaiaReauthPageIsShown();
+  tab_added_waiter.Wait();
+  target_content_observer.Wait();
+
+  content::WebContents* target_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_NE(target_contents, original_contents);
+  EXPECT_EQ(target_contents, signin_reauth_view_controller()->GetWebContents());
+  EXPECT_EQ(target_contents->GetURL(), target_url);
+
+  ASSERT_TRUE(content::ExecuteScript(
+      target_contents, "document.getElementsByTagName('a')[0].click();"));
+  EXPECT_EQ(WaitForReauthResult(), signin::ReauthResult::kSuccess);
+}
+
+// Tests that closing of the SAML tab aborts the reauth flow.
+IN_PROC_BROWSER_TEST_F(SigninReauthViewControllerBrowserTest, CloseSAMLTab) {
+  const GURL target_url =
+      https_server()->GetURL("3p-identity-provider.com", "/title1.html");
+  ShowReauthPrompt();
+  RedirectGaiaChallengeTo(target_url);
+
+  ui_test_utils::TabAddedWaiter tab_added_waiter(browser());
+  ASSERT_TRUE(login_ui_test_utils::ConfirmReauthConfirmationDialog(
+      browser(), kReauthDialogTimeout));
+  tab_added_waiter.Wait();
+
+  auto* tab_strip_model = browser()->tab_strip_model();
+  EXPECT_EQ(tab_strip_model->GetActiveWebContents()->GetURL(), target_url);
+  tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(),
+                                      TabStripModel::CLOSE_USER_GESTURE);
+  EXPECT_EQ(WaitForReauthResult(), signin::ReauthResult::kDismissedByUser);
+}
diff --git a/chrome/browser/ui/views/DEPS b/chrome/browser/ui/views/DEPS
index 27b0069..7200cc38 100644
--- a/chrome/browser/ui/views/DEPS
+++ b/chrome/browser/ui/views/DEPS
@@ -23,6 +23,5 @@
   ".*test.*": [
    "!ash",
    "+ash/public",
-   "+ash/keyboard/ui/public",
   ],
 }
diff --git a/chrome/browser/ui/views/find_bar_view.cc b/chrome/browser/ui/views/find_bar_view.cc
index 12c99104..5241034 100644
--- a/chrome/browser/ui/views/find_bar_view.cc
+++ b/chrome/browser/ui/views/find_bar_view.cc
@@ -336,8 +336,10 @@
                 find_bar_host_->GetFindBarController()->web_contents());
         find_tab_helper->StartFinding(
             find_text_->GetText(),
-            sender->GetID() == VIEW_ID_FIND_IN_PAGE_NEXT_BUTTON,
-            false);  // Not case sensitive.
+            sender->GetID() ==
+                VIEW_ID_FIND_IN_PAGE_NEXT_BUTTON, /* forward_direction */
+            false /* case_sensitive */,
+            true /* find_next_if_selection_matches */);
       }
       break;
     case VIEW_ID_FIND_IN_PAGE_CLOSE_BUTTON:
@@ -373,9 +375,10 @@
           find_in_page::FindTabHelper::FromWebContents(
               controller->web_contents());
       // Search forwards for enter, backwards for shift-enter.
-      find_tab_helper->StartFinding(find_string,
-                                    !key_event.IsShiftDown(),
-                                    false);  // Not case sensitive.
+      find_tab_helper->StartFinding(
+          find_string, !key_event.IsShiftDown() /* forward_direction */,
+          false /* case_sensitive */,
+          true /* find_next_if_selection_matches */);
     }
     return true;
   }
@@ -417,8 +420,9 @@
   // if the textbox contains something we set it as the new search string and
   // initiate search (even though old searches might be in progress).
   if (!search_text.empty()) {
-    // The last two params here are forward (true) and case sensitive (false).
-    find_tab_helper->StartFinding(search_text, true, false);
+    find_tab_helper->StartFinding(search_text, true /* forward_direction */,
+                                  false /* case_sensitive */,
+                                  true /* find_next_if_selection_matches */);
   } else {
     find_tab_helper->StopFinding(find_in_page::SelectionAction::kClear);
     UpdateForResult(find_tab_helper->find_result(), base::string16());
diff --git a/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc b/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
index 2f6b6d27..6fe6d7d6 100644
--- a/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
+++ b/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
@@ -614,8 +614,7 @@
   observer.Wait();
 }
 
-// Flaky: https://crbug.com/1072464
-IN_PROC_BROWSER_TEST_F(FindInPageTest, DISABLED_SelectionDuringFind) {
+IN_PROC_BROWSER_TEST_F(FindInPageTest, SelectionDuringFind) {
   ASSERT_TRUE(embedded_test_server()->Start());
   // Make sure Chrome is in the foreground, otherwise sending input
   // won't do anything and the test will hang.
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc
index 8702a4b..b4896a2 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc
+++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc
@@ -9,9 +9,15 @@
 #include <dwmapi.h>
 #include <uxtheme.h>
 
+#include <utility>
+
+#include "base/bind.h"
 #include "base/macros.h"
+#include "base/memory/ref_counted_delete_on_sequence.h"
 #include "base/process/process_handle.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
 #include "base/win/windows_version.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
@@ -36,6 +42,173 @@
 #include "ui/gfx/image/image_family.h"
 #include "ui/views/controls/menu/native_menu_win.h"
 
+class VirtualDesktopHelper
+    : public base::RefCountedDeleteOnSequence<VirtualDesktopHelper> {
+ public:
+  using WorkspaceChangedCallback = base::OnceCallback<void()>;
+
+  explicit VirtualDesktopHelper(const std::string& initial_workspace);
+  VirtualDesktopHelper(const VirtualDesktopHelper&) = delete;
+  VirtualDesktopHelper& operator=(const VirtualDesktopHelper&) = delete;
+
+  // public methods are all called on the UI thread.
+  void Init(HWND hwnd);
+
+  std::string GetWorkspace();
+
+  // |callback| is called when the task to get the desktop id of |hwnd|
+  // completes, if the workspace has changed.
+  void UpdateWindowDesktopId(HWND hwnd, WorkspaceChangedCallback callback);
+
+  bool GetInitialWorkspaceRemembered() const;
+
+  void SetInitialWorkspaceRemembered(bool remembered);
+
+  base::WeakPtr<VirtualDesktopHelper> AsWeakPtr();
+
+ private:
+  friend class base::RefCountedDeleteOnSequence<VirtualDesktopHelper>;
+  friend class base::DeleteHelper<VirtualDesktopHelper>;
+
+  ~VirtualDesktopHelper();
+
+  // Called on the UI thread as a task reply.
+  void SetWorkspace(WorkspaceChangedCallback callback,
+                    const std::string& workspace);
+
+  void InitImpl(HWND hwnd, const std::string& initial_workspace);
+
+  static std::string GetWindowDesktopIdImpl(
+      HWND hwnd,
+      Microsoft::WRL::ComPtr<IVirtualDesktopManager> virtual_desktop_manager);
+
+  // All member variables, except where noted, are only accessed on the ui
+  // thead.
+
+  // Workspace browser window was opened on. This is used to tell the
+  // BrowserWindowState about the initial workspace, which has to happen after
+  // |this| is fully set up.
+  const std::string initial_workspace_;
+
+  // On Windows10, this is the virtual desktop the browser window was on,
+  // last we checked. This is used to tell if the window has moved to a
+  // different desktop, and notify listeners. It will only be set if
+  // we created |virtual_desktop_helper_|.
+  base::Optional<std::string> workspace_;
+
+  bool initial_workspace_remembered_ = false;
+
+  // Only set on Windows 10. This is created and accessed on a separate
+  // COMSTAT thread. It will be null if creation failed.
+  Microsoft::WRL::ComPtr<IVirtualDesktopManager> virtual_desktop_manager_;
+
+  base::WeakPtrFactory<VirtualDesktopHelper> weak_factory_{this};
+};
+
+VirtualDesktopHelper::VirtualDesktopHelper(const std::string& initial_workspace)
+    : base::RefCountedDeleteOnSequence<VirtualDesktopHelper>(
+          base::ThreadPool::CreateCOMSTATaskRunner({base::MayBlock()})),
+      initial_workspace_(initial_workspace) {}
+
+void VirtualDesktopHelper::Init(HWND hwnd) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  owning_task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&VirtualDesktopHelper::InitImpl, this, hwnd,
+                                initial_workspace_));
+}
+
+VirtualDesktopHelper::~VirtualDesktopHelper() {}
+
+std::string VirtualDesktopHelper::GetWorkspace() {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  if (!workspace_.has_value())
+    workspace_ = initial_workspace_;
+
+  return workspace_.value_or(std::string());
+}
+
+void VirtualDesktopHelper::UpdateWindowDesktopId(
+    HWND hwnd,
+    WorkspaceChangedCallback callback) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  owning_task_runner()->PostTaskAndReplyWithResult(
+      FROM_HERE,
+      base::BindOnce(&VirtualDesktopHelper::GetWindowDesktopIdImpl, hwnd,
+                     virtual_desktop_manager_),
+      base::BindOnce(&VirtualDesktopHelper::SetWorkspace, AsWeakPtr(),
+                     base::Passed(std::move(callback))));
+}
+
+bool VirtualDesktopHelper::GetInitialWorkspaceRemembered() const {
+  return initial_workspace_remembered_;
+}
+
+void VirtualDesktopHelper::SetInitialWorkspaceRemembered(bool remembered) {
+  initial_workspace_remembered_ = remembered;
+}
+
+base::WeakPtr<VirtualDesktopHelper> VirtualDesktopHelper::AsWeakPtr() {
+  return weak_factory_.GetWeakPtr();
+}
+
+void VirtualDesktopHelper::SetWorkspace(WorkspaceChangedCallback callback,
+                                        const std::string& workspace) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  // If GetWindowDesktopId() fails, |workspace| will be empty, and it's most
+  // likely that the current value of |workspace_| is still correct, so don't
+  // overwrite it.
+  if (workspace.empty())
+    return;
+
+  bool workspace_changed = workspace != workspace_.value_or(std::string());
+  workspace_ = workspace;
+  if (workspace_changed)
+    std::move(callback).Run();
+}
+
+void VirtualDesktopHelper::InitImpl(HWND hwnd,
+                                    const std::string& initial_workspace) {
+  DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  // Virtual Desktops on Windows are best-effort and may not always be
+  // available.
+  if (FAILED(::CoCreateInstance(__uuidof(::VirtualDesktopManager), nullptr,
+                                CLSCTX_ALL,
+                                IID_PPV_ARGS(&virtual_desktop_manager_))) ||
+      initial_workspace.empty()) {
+    return;
+  }
+  GUID guid = GUID_NULL;
+  HRESULT hr =
+      CLSIDFromString(base::UTF8ToUTF16(initial_workspace).c_str(), &guid);
+  if (SUCCEEDED(hr)) {
+    // There are valid reasons MoveWindowToDesktop can fail, e.g.,
+    // the desktop was deleted. If it fails, the window will open on the
+    // current desktop.
+    virtual_desktop_manager_->MoveWindowToDesktop(hwnd, guid);
+  }
+}
+
+// static
+std::string VirtualDesktopHelper::GetWindowDesktopIdImpl(
+    HWND hwnd,
+    Microsoft::WRL::ComPtr<IVirtualDesktopManager> virtual_desktop_manager) {
+  DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  if (!virtual_desktop_manager)
+    return std::string();
+
+  GUID workspace_guid;
+  HRESULT hr =
+      virtual_desktop_manager->GetWindowDesktopId(hwnd, &workspace_guid);
+  if (FAILED(hr) || workspace_guid == GUID_NULL)
+    return std::string();
+
+  LPOLESTR workspace_widestr;
+  StringFromCLSID(workspace_guid, &workspace_widestr);
+  std::string workspace_id = base::WideToUTF8(workspace_widestr);
+  CoTaskMemFree(workspace_widestr);
+  return workspace_id;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // BrowserDesktopWindowTreeHostWin, public:
 
@@ -47,7 +220,8 @@
     : DesktopWindowTreeHostWin(native_widget_delegate,
                                desktop_native_widget_aura),
       browser_view_(browser_view),
-      browser_frame_(browser_frame) {
+      browser_frame_(browser_frame),
+      virtual_desktop_helper_(nullptr) {
   profile_observer_.Add(
       &g_browser_process->profile_manager()->GetProfileAttributesStorage());
 
@@ -95,45 +269,28 @@
     const views::Widget::InitParams& params) {
   DesktopWindowTreeHostWin::Init(params);
   if (base::win::GetVersion() < base::win::Version::WIN10)
-    return;  // VirtualDesktopManager isn't support pre Win-10.
+    return;  // VirtualDesktopManager isn't supported pre Win-10.
 
-  // Virtual Desktops on Windows are best-effort and may not always be
-  // available.
-  if (FAILED(::CoCreateInstance(__uuidof(VirtualDesktopManager), nullptr,
-                                CLSCTX_ALL,
-                                IID_PPV_ARGS(&virtual_desktop_manager_)))) {
-    return;
-  }
+  virtual_desktop_helper_ = new VirtualDesktopHelper(params.workspace);
+  virtual_desktop_helper_->Init(GetHWND());
+}
 
-  if (!params.workspace.empty()) {
-    GUID guid = GUID_NULL;
-    HRESULT hr =
-        CLSIDFromString(base::UTF8ToUTF16(params.workspace).c_str(), &guid);
-    if (SUCCEEDED(hr)) {
-      // There are valid reasons MoveWindowToDesktop can fail, e.g.,
-      // the desktop was deleted. If it fails, the window will open on the
-      // current desktop.
-      virtual_desktop_manager_->MoveWindowToDesktop(GetHWND(), guid);
-    }
+void BrowserDesktopWindowTreeHostWin::Show(ui::WindowShowState show_state,
+                                           const gfx::Rect& restore_bounds) {
+  // This will make BrowserWindowState remember the initial workspace.
+  // It has to be called after DesktopNativeWidgetAura is observing the host
+  // and the session service is tracking the window.
+  if (virtual_desktop_helper_ &&
+      !virtual_desktop_helper_->GetInitialWorkspaceRemembered()) {
+    OnHostWorkspaceChanged();
+    virtual_desktop_helper_->SetInitialWorkspaceRemembered(true);
   }
+  DesktopWindowTreeHostWin::Show(show_state, restore_bounds);
 }
 
 std::string BrowserDesktopWindowTreeHostWin::GetWorkspace() const {
-  std::string workspace_id;
-  if (virtual_desktop_manager_) {
-    GUID workspace_guid;
-    HRESULT hr = virtual_desktop_manager_->GetWindowDesktopId(GetHWND(),
-                                                              &workspace_guid);
-    if (FAILED(hr) || workspace_guid == GUID_NULL)
-      return workspace_.value_or("");
-
-    LPOLESTR workspace_widestr;
-    StringFromCLSID(workspace_guid, &workspace_widestr);
-    workspace_id = base::WideToUTF8(workspace_widestr);
-    workspace_ = workspace_id;
-    CoTaskMemFree(workspace_widestr);
-  }
-  return workspace_id;
+  return virtual_desktop_helper_ ? virtual_desktop_helper_->GetWorkspace()
+                                 : std::string();
 }
 
 int BrowserDesktopWindowTreeHostWin::GetInitialShowState() const {
@@ -225,11 +382,6 @@
 }
 
 void BrowserDesktopWindowTreeHostWin::HandleDestroying() {
-  // TODO(crbug/976176): Move all access to |virtual_desktop_manager_| off of
-  // the ui thread to prevent reentrancy bugs due to COM objects pumping
-  // messages. For now, Reset() so COM object destructor is called before
-  // |this| is in the process of being deleted.
-  virtual_desktop_manager_.Reset();
   browser_window_property_manager_.reset();
   DesktopWindowTreeHostWin::HandleDestroying();
 }
@@ -272,10 +424,13 @@
                                                     LPARAM l_param) {
   switch (message) {
     case WM_SETFOCUS: {
-      // GetWorkspace sets |workspace_|, so stash prev value.
-      std::string prev_workspace = workspace_.value_or("");
-      if (prev_workspace != GetWorkspace())
-        OnHostWorkspaceChanged();
+      if (virtual_desktop_helper_) {
+        virtual_desktop_helper_->UpdateWindowDesktopId(
+            GetHWND(),
+            base::BindOnce(
+                &BrowserDesktopWindowTreeHostWin::OnHostWorkspaceChanged,
+                weak_factory_.GetWeakPtr()));
+      }
       break;
     }
     case WM_CREATE:
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.h b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.h
index 5968e03..40a5c3f5 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.h
+++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.h
@@ -8,8 +8,13 @@
 #include <shobjidl.h>
 #include <wrl/client.h>
 
+#include <memory>
+#include <string>
+
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
+#include "base/sequenced_task_runner.h"
 #include "base/win/scoped_gdi_object.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/ui/views/frame/browser_desktop_window_tree_host.h"
@@ -19,6 +24,7 @@
 class BrowserFrame;
 class BrowserView;
 class BrowserWindowPropertyManager;
+class VirtualDesktopHelper;
 
 namespace views {
 class DesktopNativeWidgetAura;
@@ -35,6 +41,10 @@
       views::DesktopNativeWidgetAura* desktop_native_widget_aura,
       BrowserView* browser_view,
       BrowserFrame* browser_frame);
+  BrowserDesktopWindowTreeHostWin(const BrowserDesktopWindowTreeHostWin&) =
+      delete;
+  BrowserDesktopWindowTreeHostWin& operator=(
+      const BrowserDesktopWindowTreeHostWin&) = delete;
   ~BrowserDesktopWindowTreeHostWin() override;
 
  private:
@@ -47,6 +57,8 @@
 
   // Overridden from DesktopWindowTreeHostWin:
   void Init(const views::Widget::InitParams& params) override;
+  void Show(ui::WindowShowState show_state,
+            const gfx::Rect& restore_bounds) override;
   std::string GetWorkspace() const override;
   int GetInitialShowState() const override;
   bool GetClientAreaInsets(gfx::Insets* insets,
@@ -86,16 +98,6 @@
   // The wrapped system menu itself.
   std::unique_ptr<views::NativeMenuWin> system_menu_;
 
-  // On Windows10, this is the virtual desktop the browser window was on,
-  // last we checked. This is used to tell if the window has moved to a
-  // different desktop, and notify listeners. It will only be set if
-  // we created |virtual_desktop_manager_|.
-  mutable base::Optional<std::string> workspace_;
-
-  // Only set on Windows10. Set by GetOrCreateVirtualDesktopManager().
-  mutable Microsoft::WRL::ComPtr<IVirtualDesktopManager>
-      virtual_desktop_manager_;
-
   // This is used to monitor when the window icon needs to be updated because
   // the icon badge has changed (e.g., avatar icon changed).
   ScopedObserver<ProfileAttributesStorage, ProfileAttributesStorage::Observer>
@@ -103,7 +105,10 @@
 
   base::win::ScopedHICON icon_handle_;
 
-  DISALLOW_COPY_AND_ASSIGN(BrowserDesktopWindowTreeHostWin);
+  // This will be null pre Win10.
+  scoped_refptr<VirtualDesktopHelper> virtual_desktop_helper_;
+
+  base::WeakPtrFactory<BrowserDesktopWindowTreeHostWin> weak_factory_{this};
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_DESKTOP_WINDOW_TREE_HOST_WIN_H_
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
index 0404d86..62f8d7f 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
@@ -211,8 +211,10 @@
 
 // Verify the immersive mode status is as expected in tablet mode (titlebars are
 // autohidden in tablet mode).
+
+// Crashes on Linux Chromium OS ASan LSan Tests.  http://crbug.com/1091606
 IN_PROC_BROWSER_TEST_P(ImmersiveModeControllerAshWebAppBrowserTest,
-                       ImmersiveModeStatusTabletMode) {
+                       DISABLED_ImmersiveModeStatusTabletMode) {
   LaunchAppBrowser();
   ASSERT_FALSE(controller()->IsEnabled());
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index ec6bf7c..ae14dd39 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -109,8 +109,9 @@
   static const char kKey[];
 
   OmniboxState(const OmniboxEditModel::State& model_state,
-               const gfx::Range& selection,
-               const gfx::Range& saved_selection_for_focus_change);
+               const std::vector<gfx::Range> selection,
+               const std::vector<gfx::Range> saved_selection_for_focus_change);
+
   ~OmniboxState() override;
 
   const OmniboxEditModel::State model_state;
@@ -119,23 +120,22 @@
   // omnibox is not focused).  This allows us to properly handle cases like
   // selecting text, tabbing out of the omnibox, switching tabs away and back,
   // and tabbing back into the omnibox.
-  const gfx::Range selection;
-  const gfx::Range saved_selection_for_focus_change;
+  const std::vector<gfx::Range> selection;
+  const std::vector<gfx::Range> saved_selection_for_focus_change;
 };
 
 // static
 const char OmniboxState::kKey[] = "OmniboxState";
 
-OmniboxState::OmniboxState(const OmniboxEditModel::State& model_state,
-                           const gfx::Range& selection,
-                           const gfx::Range& saved_selection_for_focus_change)
+OmniboxState::OmniboxState(
+    const OmniboxEditModel::State& model_state,
+    const std::vector<gfx::Range> selection,
+    const std::vector<gfx::Range> saved_selection_for_focus_change)
     : model_state(model_state),
       selection(selection),
-      saved_selection_for_focus_change(saved_selection_for_focus_change) {
-}
+      saved_selection_for_focus_change(saved_selection_for_focus_change) {}
 
-OmniboxState::~OmniboxState() {
-}
+OmniboxState::~OmniboxState() = default;
 
 enum OmniboxMenuCommands {
   kShowUrl = views::Textfield::MenuCommands::kLastCommandId + 1,
@@ -213,7 +213,6 @@
                                    const gfx::FontList& font_list)
     : OmniboxView(controller, std::move(client)),
       popup_window_mode_(popup_window_mode),
-      saved_selection_for_focus_change_(gfx::Range::InvalidRange()),
       location_bar_view_(location_bar),
       latency_histogram_state_(NOT_ACTIVE),
       friendly_suggestion_text_prefix_length_(0) {
@@ -285,9 +284,10 @@
   // NOTE: GetStateForTabSwitch() may affect GetSelectedRange(), so order is
   // important.
   OmniboxEditModel::State state = model()->GetStateForTabSwitch();
-  tab->SetUserData(OmniboxState::kKey, std::make_unique<OmniboxState>(
-                                           state, GetSelectedRange(),
-                                           saved_selection_for_focus_change_));
+  tab->SetUserData(
+      OmniboxState::kKey,
+      std::make_unique<OmniboxState>(state, GetRenderText()->GetAllSelections(),
+                                     saved_selection_for_focus_change_));
 }
 
 void OmniboxViewViews::OnTabChanged(const content::WebContents* web_contents) {
@@ -305,9 +305,9 @@
       // See comment in OmniboxEditModel::GetStateForTabSwitch() for details on
       // this.
       SelectAll(true);
-      saved_selection_for_focus_change_ = gfx::Range();
+      saved_selection_for_focus_change_.clear();
     } else {
-      SetSelectedRange(state->selection);
+      SetSelectedRanges(state->selection);
       saved_selection_for_focus_change_ =
           state->saved_selection_for_focus_change;
     }
@@ -399,7 +399,7 @@
 
 void OmniboxViewViews::SetUserText(const base::string16& text,
                                    bool update_popup) {
-  saved_selection_for_focus_change_ = gfx::Range::InvalidRange();
+  saved_selection_for_focus_change_.clear();
   OmniboxView::SetUserText(text, update_popup);
 }
 
@@ -417,12 +417,19 @@
   *end = static_cast<size_t>(range.end());
 }
 
+size_t OmniboxViewViews::GetAllSelectionsLength() const {
+  size_t sum = 0;
+  for (auto s : GetRenderText()->GetAllSelections())
+    sum += s.length();
+  return sum;
+}
+
 void OmniboxViewViews::SelectAll(bool reversed) {
   views::Textfield::SelectAll(reversed);
 }
 
 void OmniboxViewViews::RevertAll() {
-  saved_selection_for_focus_change_ = gfx::Range::InvalidRange();
+  saved_selection_for_focus_change_.clear();
   OmniboxView::RevertAll();
 }
 
@@ -615,8 +622,10 @@
   return HasTextBeingDragged();
 }
 
-void OmniboxViewViews::SetTextAndSelectedRange(const base::string16& text,
-                                               const gfx::Range& range) {
+void OmniboxViewViews::SetTextAndSelectedRanges(
+    const base::string16& text,
+    const std::vector<gfx::Range>& ranges,
+    const base::string16& additional_text) {
   // Will try to fit as much of unselected text as possible. If possible,
   // guarantees at least |pad_left| chars of the unselected text are visible. If
   // possible given the prior guarantee, also guarantees |pad_right| chars of
@@ -624,19 +633,39 @@
   static const uint32_t kPadRight = 30;
   static const uint32_t kPadLeft = 10;
 
-  SetText(text);
+  SetText(text, ranges[0].end());
   // Select all the text to prioritize showing unselected text.
-  SetSelectedRange(gfx::Range(range.start(), 0));
-  // Scroll selection right, to ensure |kPadRight| chars of selected text are
-  // shown.
-  SetSelectedRange(gfx::Range(
-      range.start(), std::min(range.end() + kPadRight, range.start())));
-  // Scroll selection left, to ensure |kPadLeft| chars of unselected text are
+  SetSelectedRange(gfx::Range(ranges[0].start(), 0));
+  // Scroll range right, to ensure |kPadRight| chars of selected text are
   // shown.
   SetSelectedRange(
-      gfx::Range(range.start(), range.end() - std::min(kPadLeft, range.end())));
-  // Select the specified selection.
-  SetSelectedRange(range);
+      gfx::Range(ranges[0].start(),
+                 std::min(ranges[0].end() + kPadRight, ranges[0].start())));
+  // Scroll range left, to ensure |kPadLeft| chars of unselected text are
+  // shown.
+  SetSelectedRange(
+      gfx::Range(ranges[0].start(),
+                 ranges[0].end() - std::min(kPadLeft, ranges[0].end())));
+  // Select the specified ranges.
+  SetSelectedRanges(ranges);
+  // Set the additional text.
+  // TODO (manukh): Ideally, OmniboxView wouldn't be responsible for its sibling
+  // label owned by LocationBarView. However, this is the only practical pathway
+  // between the OmniboxEditModel, which handles setting the omnibox match, and
+  // LocationBarView. Perhaps, if we decide to launch rich autocompletion we'll
+  // consider alternatives.
+  location_bar_view_->SetOmniboxAdditionalText(additional_text);
+}
+
+void OmniboxViewViews::SetSelectedRanges(
+    const std::vector<gfx::Range>& ranges) {
+  // Even when no text is selected, |ranges| should have at least 1 (empty)
+  // Range representing the cursor.
+  DCHECK(!ranges.empty());
+
+  SetSelectedRange(ranges[0]);
+  for (size_t i = 1; i < ranges.size(); i++)
+    SetSelectedRange(ranges[i], false);
 }
 
 base::string16 OmniboxViewViews::GetSelectedText() const {
@@ -743,12 +772,14 @@
       ->MaybeTriggerSecondaryButton(event);
 }
 
-void OmniboxViewViews::SetWindowTextAndCaretPos(const base::string16& text,
-                                                size_t caret_pos,
-                                                bool update_popup,
-                                                bool notify_text_changed) {
-  const gfx::Range range(caret_pos, caret_pos);
-  SetTextAndSelectedRange(text, range);
+void OmniboxViewViews::SetWindowTextAndCaretPos(
+    const base::string16& text,
+    size_t caret_pos,
+    bool update_popup,
+    bool notify_text_changed,
+    const base::string16& additional_text) {
+  const gfx::Range range(caret_pos);
+  SetTextAndSelectedRanges(text, {range}, additional_text);
 
   if (update_popup)
     UpdatePopup();
@@ -789,27 +820,32 @@
     bool save_original_selection,
     bool notify_text_changed) {
   if (save_original_selection)
-    saved_temporary_selection_ = GetSelectedRange();
+    saved_temporary_selection_ = GetRenderText()->GetAllSelections();
   SetAccessibilityLabel(display_text, match);
   SetWindowTextAndCaretPos(display_text, display_text.length(), false,
                            notify_text_changed);
 }
 
-bool OmniboxViewViews::OnInlineAutocompleteTextMaybeChanged(
+void OmniboxViewViews::OnInlineAutocompleteTextMaybeChanged(
     const base::string16& display_text,
-    size_t user_text_length) {
+    size_t user_text_length,
+    size_t user_text_start,
+    const base::string16& additional_text) {
   if (display_text == GetText())
-    return false;
+    return;
 
   if (!IsIMEComposing()) {
-    gfx::Range range(display_text.size(), user_text_length);
-    SetTextAndSelectedRange(display_text, range);
+    std::vector<gfx::Range> ranges = {
+        {display_text.size(), user_text_length + user_text_start}};
+    if (user_text_start)
+      ranges.push_back({0, user_text_start});
+    SetTextAndSelectedRanges(display_text, ranges, additional_text);
   } else if (location_bar_view_) {
     location_bar_view_->SetImeInlineAutocompletion(
         display_text.substr(user_text_length));
   }
-  TextChanged();
-  return true;
+
+  EmphasizeURLComponents();
 }
 
 void OmniboxViewViews::OnInlineAutocompleteTextCleared() {
@@ -821,7 +857,8 @@
 void OmniboxViewViews::OnRevertTemporaryText(const base::string16& display_text,
                                              const AutocompleteMatch& match) {
   SetAccessibilityLabel(display_text, match);
-  SetSelectedRange(saved_temporary_selection_);
+  SetSelectedRanges(saved_temporary_selection_);
+
   // We got here because the user hit the Escape key. We explicitly don't call
   // TextChanged(), since OmniboxPopupModel::ResetToDefaultMatch() has already
   // been called by now, and it would've called TextChanged() if it was
@@ -1102,8 +1139,6 @@
   return kViewClassName;
 }
 
-// TODO (manukh) These OnMouse* functions should be reordered to match the
-// header.
 bool OmniboxViewViews::OnMousePressed(const ui::MouseEvent& event) {
   if (model()->popup_model()) {  // Can be null in tests.
     model()->popup_model()->ClearSelectionState();
@@ -1125,7 +1160,7 @@
     // possible to later set select_all_on_mouse_release_ back to false, but
     // that happens for things like dragging, which are cases where having
     // invalidated this saved selection is still OK.
-    saved_selection_for_focus_change_ = gfx::Range::InvalidRange();
+    saved_selection_for_focus_change_.clear();
   }
 
   // Show on-focus suggestions if either:
@@ -1201,7 +1236,7 @@
 
     // If we're trying to select all on tap, invalidate any saved selection lest
     // restoring it fights with the "select all" action.
-    saved_selection_for_focus_change_ = gfx::Range::InvalidRange();
+    saved_selection_for_focus_change_.clear();
   }
 
   // Show on-focus suggestions if either:
@@ -1290,9 +1325,9 @@
   base::string16::size_type entry_end;
   // Selection information is saved separately when focus is moved off the
   // current window - use that when there is no focus and it's valid.
-  if (saved_selection_for_focus_change_.IsValid()) {
-    entry_start = saved_selection_for_focus_change_.start();
-    entry_end = saved_selection_for_focus_change_.end();
+  if (!saved_selection_for_focus_change_.empty()) {
+    entry_start = saved_selection_for_focus_change_[0].start();
+    entry_end = saved_selection_for_focus_change_[0].end();
   } else {
     GetSelectionBounds(&entry_start, &entry_end);
   }
@@ -1320,9 +1355,9 @@
     return true;
   } else if (action_data.action == ax::mojom::Action::kReplaceSelectedText) {
     model()->SetInputInProgress(true);
-    if (saved_selection_for_focus_change_.IsValid()) {
-      SetSelectedRange(saved_selection_for_focus_change_);
-      saved_selection_for_focus_change_ = gfx::Range::InvalidRange();
+    if (!saved_selection_for_focus_change_.empty()) {
+      SetSelectedRanges(saved_selection_for_focus_change_);
+      saved_selection_for_focus_change_.clear();
     }
     InsertOrReplaceText(base::UTF8ToUTF16(action_data.value));
     TextChanged();
@@ -1354,9 +1389,9 @@
   // Don't call controller()->OnSetFocus, this view has already acquired focus.
 
   // Restore the selection we saved in OnBlur() if it's still valid.
-  if (saved_selection_for_focus_change_.IsValid()) {
-    SetSelectedRange(saved_selection_for_focus_change_);
-    saved_selection_for_focus_change_ = gfx::Range::InvalidRange();
+  if (!saved_selection_for_focus_change_.empty()) {
+    SetSelectedRanges(saved_selection_for_focus_change_);
+    saved_selection_for_focus_change_.clear();
   }
 
   GetRenderText()->SetElideBehavior(gfx::NO_ELIDE);
@@ -1386,7 +1421,7 @@
 
 void OmniboxViewViews::OnBlur() {
   // Save the user's existing selection to restore it later.
-  saved_selection_for_focus_change_ = GetSelectedRange();
+  saved_selection_for_focus_change_ = GetRenderText()->GetAllSelections();
 
   // popup_model() can be null in tests.
   OmniboxPopupModel* popup_model = model()->popup_model();
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.h b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
index 71fdea2..c28000b 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
@@ -120,14 +120,17 @@
   using OmniboxView::SetUserText;
   void SetUserText(const base::string16& text,
                    bool update_popup) override;
-  void SetWindowTextAndCaretPos(const base::string16& text,
-                                size_t caret_pos,
-                                bool update_popup,
-                                bool notify_text_changed) override;
+  void SetWindowTextAndCaretPos(
+      const base::string16& text,
+      size_t caret_pos,
+      bool update_popup,
+      bool notify_text_changed,
+      const base::string16& additional_text = base::string16()) override;
   void EnterKeywordModeForDefaultSearchProvider() override;
   bool IsSelectAll() const override;
   void GetSelectionBounds(base::string16::size_type* start,
                           base::string16::size_type* end) const override;
+  size_t GetAllSelectionsLength() const override;
   void SelectAll(bool reversed) override;
   void RevertAll() override;
   void SetFocus(bool is_user_initiated) override;
@@ -174,9 +177,15 @@
     OTHER,
   };
 
-  // Update the field with |text| and set the selection.
-  void SetTextAndSelectedRange(const base::string16& text,
-                               const gfx::Range& range);
+  // Update the field with |text| and set the selection. |ranges| should not be
+  // empty; even text with no selections must have at least 1 empty range in
+  // |ranges| to indicate the cursor position.
+  void SetTextAndSelectedRanges(
+      const base::string16& text,
+      const std::vector<gfx::Range>& ranges,
+      const base::string16& additional_text = base::string16());
+
+  void SetSelectedRanges(const std::vector<gfx::Range>& ranges);
 
   // Returns the selected text.
   base::string16 GetSelectedText() const;
@@ -223,8 +232,11 @@
                                    const AutocompleteMatch& match,
                                    bool save_original_selection,
                                    bool notify_text_changed) override;
-  bool OnInlineAutocompleteTextMaybeChanged(const base::string16& display_text,
-                                            size_t user_text_length) override;
+  void OnInlineAutocompleteTextMaybeChanged(
+      const base::string16& display_text,
+      size_t user_text_length,
+      size_t user_text_start = 0,
+      const base::string16& additional_text = base::string16()) override;
   void OnInlineAutocompleteTextCleared() override;
   void OnRevertTemporaryText(const base::string16& display_text,
                              const AutocompleteMatch& match) override;
@@ -304,11 +316,11 @@
   std::unique_ptr<PathFadeAnimation> path_fade_animation_;
 
   // Selection persisted across temporary text changes, like popup suggestions.
-  gfx::Range saved_temporary_selection_;
+  std::vector<gfx::Range> saved_temporary_selection_;
 
   // Holds the user's selection across focus changes.  There is only a saved
   // selection if this range IsValid().
-  gfx::Range saved_selection_for_focus_change_;
+  std::vector<gfx::Range> saved_selection_for_focus_change_;
 
   // Tracking state before and after a possible change.
   State state_before_change_;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
index ff217df9..8700d9e 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -706,6 +706,38 @@
   EXPECT_TRUE(omnibox_view()->IsSelectAll());
 }
 
+TEST_F(OmniboxViewViewsTest, SetWindowTextAndCaretPos) {
+  // googl|e.com
+  omnibox_view()->SetWindowTextAndCaretPos(base::UTF8ToUTF16("google.com"), 5,
+                                           false, false);
+  EXPECT_EQ(base::ASCIIToUTF16("google.com"), omnibox_view()->GetText());
+  EXPECT_EQ(omnibox_view()->GetRenderText()->GetAllSelections(),
+            (std::vector<Range>{{5, 5}}));
+}
+
+TEST_F(OmniboxViewViewsTest, OnInlineAutocompleteTextMaybeChanged) {
+  // No selection, google.com|
+  omnibox_view()->OnInlineAutocompleteTextMaybeChanged(
+      base::UTF8ToUTF16("google.com"), 10);
+  EXPECT_EQ(base::ASCIIToUTF16("google.com"), omnibox_view()->GetText());
+  EXPECT_EQ(omnibox_view()->GetRenderText()->GetAllSelections(),
+            (std::vector<Range>{{10, 10}}));
+
+  // Single selection, gmai[l.com]
+  omnibox_view()->OnInlineAutocompleteTextMaybeChanged(
+      base::UTF8ToUTF16("gmail.com"), 4);
+  EXPECT_EQ(base::ASCIIToUTF16("gmail.com"), omnibox_view()->GetText());
+  EXPECT_EQ(omnibox_view()->GetRenderText()->GetAllSelections(),
+            (std::vector<Range>{{9, 4}}));
+
+  // Multiselection, [go]ogl[e.com]
+  omnibox_view()->OnInlineAutocompleteTextMaybeChanged(
+      base::UTF8ToUTF16("google.com"), 3, 2);
+  EXPECT_EQ(base::ASCIIToUTF16("google.com"), omnibox_view()->GetText());
+  EXPECT_EQ(omnibox_view()->GetRenderText()->GetAllSelections(),
+            (std::vector<Range>{{10, 5}, {0, 2}}));
+}
+
 class OmniboxViewViewsClipboardTest
     : public OmniboxViewViewsTest,
       public ::testing::WithParamInterface<ui::TextEditCommand> {
@@ -1314,6 +1346,7 @@
   EXPECT_FALSE(omnibox_view()->scheme_range().IsValid());
 }
 
+// TODO (manukh) move up to where the other OmniboxViewViewsTest tests are.
 TEST_F(OmniboxViewViewsTest, OverflowingAutocompleteText) {
   // Make the Omnibox narrow so it can't fit the entire string (~650px), but
   // wide enough to fit the user text (~65px).
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer.mojom b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer.mojom
index e679865..72e63a9 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer.mojom
+++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer.mojom
@@ -25,10 +25,15 @@
   // If a user cancels the installation without starting it at all, this should
   // be called so that metrics can be recorded.
   CancelBeforeStart();
-  // The page normally is displayed in a dialog. Call this to close the dialog.
-  // chrome.send('dialogClose') should not be used, which could kill the page
-  // handler before previous mojom calls have been run.
-  Close();
+  // This is called when the web page is "closed", and the dialog (or whatever)
+  // hosting it should also be closed. This can happen as a result of
+  // Page::RequestClose() being called, or it can happen spontaneously (e.g.
+  // user clicking cancel on the page or installation finished).
+  //
+  // Note that the web page should not use something like
+  // chrome.send('dialogClose'), which could kill the page handler before
+  // previous mojom calls have been run.
+  OnPageClosed();
   // Fetches the amount of free disk space, the result is sent via
   // OnAmountOfFreeDiskSpace.
   RequestAmountOfFreeDiskSpace();
@@ -54,4 +59,7 @@
   OnAmountOfFreeDiskSpace(array<crostini.mojom.DiskSliderTick> ticks,
                           int8 default_index,
                           bool is_low_space_available);
+  // Informs the page that it should be closed. The page should respond with
+  // PageHandler::OnPageClosed() to indicate it is ready to be closed.
+  RequestClose();
 };
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.cc b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.cc
index b3f75d2..4c0d0fc 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.cc
+++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.cc
@@ -82,7 +82,14 @@
   // closing logic, we should find a more general solution.
 
   // Disallow closing without WebUI consent.
-  return installer_ui_ == nullptr || installer_ui_->can_close();
+  //
+  // Note that while the function name |CanCloseDialog| does not indicate the
+  // intend to close the dialog, but it is indeed only called when we are
+  // closing it, so requesting closing the page here is appropriate. One might
+  // think we should actually do all of this in |OnDialogCloseRequested|
+  // instead, but unfortunately that function is called after the web content is
+  // closed.
+  return installer_ui_ == nullptr || installer_ui_->RequestClosePage();
 }
 
 void CrostiniInstallerDialog::OnDialogShown(content::WebUI* webui) {
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.cc b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.cc
index 0bd746d..993fb22 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.cc
@@ -29,11 +29,11 @@
     mojo::PendingReceiver<chromeos::crostini_installer::mojom::PageHandler>
         pending_page_handler,
     mojo::PendingRemote<chromeos::crostini_installer::mojom::Page> pending_page,
-    base::OnceClosure close_dialog_callback)
+    base::OnceClosure on_page_closed)
     : installer_ui_delegate_{installer_ui_delegate},
       receiver_{this, std::move(pending_page_handler)},
       page_{std::move(pending_page)},
-      close_dialog_callback_{std::move(close_dialog_callback)} {}
+      on_page_closed_{std::move(on_page_closed)} {}
 
 CrostiniInstallerPageHandler::~CrostiniInstallerPageHandler() = default;
 
@@ -64,9 +64,9 @@
   installer_ui_delegate_->CancelBeforeStart();
 }
 
-void CrostiniInstallerPageHandler::Close() {
-  if (close_dialog_callback_) {
-    std::move(close_dialog_callback_).Run();
+void CrostiniInstallerPageHandler::OnPageClosed() {
+  if (on_page_closed_) {
+    std::move(on_page_closed_).Run();
   }
 }
 
@@ -94,6 +94,10 @@
                      weak_ptr_factory_.GetWeakPtr()));
 }
 
+void CrostiniInstallerPageHandler::RequestClosePage() {
+  page_->RequestClose();
+}
+
 void CrostiniInstallerPageHandler::OnAmountOfFreeDiskSpace(int64_t free_bytes) {
   int64_t max_bytes = free_bytes - crostini::disk::kDiskHeadroomBytes;
 
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.h b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.h
index 94128cd4..8794f3de 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.h
+++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.h
@@ -30,16 +30,19 @@
           pending_page_handler,
       mojo::PendingRemote<chromeos::crostini_installer::mojom::Page>
           pending_page,
-      base::OnceClosure close_dialog_callback);
+      base::OnceClosure on_page_closed);
   ~CrostiniInstallerPageHandler() override;
 
   // chromeos::crostini_installer::mojom::PageHandler:
   void Install(int64_t disk_size_bytes, const std::string& username) override;
   void Cancel() override;
   void CancelBeforeStart() override;
-  void Close() override;
+  void OnPageClosed() override;
   void RequestAmountOfFreeDiskSpace() override;
 
+  // Send a close request to the web page.
+  void RequestClosePage();
+
  private:
   void OnProgressUpdate(crostini::mojom::InstallerState installer_state,
                         double progress_fraction);
@@ -50,7 +53,7 @@
   crostini::CrostiniInstallerUIDelegate* installer_ui_delegate_;
   mojo::Receiver<chromeos::crostini_installer::mojom::PageHandler> receiver_;
   mojo::Remote<chromeos::crostini_installer::mojom::Page> page_;
-  base::OnceClosure close_dialog_callback_;
+  base::OnceClosure on_page_closed_;
 
   base::WeakPtrFactory<CrostiniInstallerPageHandler> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.cc b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.cc
index 47cab7a..0845f8c 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.cc
@@ -84,6 +84,7 @@
        IDS_CROSTINI_INSTALLER_USERNAME_INVALID_CHARACTERS_ERROR},
       {"usernameNotAvailableError",
        IDS_CROSTINI_INSTALLER_USERNAME_NOT_AVAILABLE_ERROR},
+      {"customDiskSizeLabel", IDS_CROSTINI_INSTALLER_CUSTOM_DISK_SIZE_LABEL},
   };
   AddLocalizedStringsBulk(source, kStrings);
 
@@ -117,6 +118,13 @@
           ui::FormatBytesWithUnits(crostini::disk::kRecommendedDiskSizeBytes,
                                    ui::DATA_UNITS_GIBIBYTE,
                                    /*show_units=*/true)));
+  source->AddString(
+      "recommendedDiskSizeLabel",
+      l10n_util::GetStringFUTF8(
+          IDS_CROSTINI_INSTALLER_RECOMMENDED_DISK_SIZE_LABEL,
+          ui::FormatBytesWithUnits(crostini::disk::kRecommendedDiskSizeBytes,
+                                   ui::DATA_UNITS_GIBIBYTE,
+                                   /*show_units=*/true)));
   source->AddString("offlineError",
                     l10n_util::GetStringFUTF8(
                         IDS_CROSTINI_INSTALLER_OFFLINE_ERROR, device_name));
@@ -162,8 +170,13 @@
 
 CrostiniInstallerUI::~CrostiniInstallerUI() = default;
 
-bool CrostiniInstallerUI::can_close() {
-  return can_close_;
+bool CrostiniInstallerUI::RequestClosePage() {
+  if (page_closed_ || !page_handler_) {
+    return true;
+  }
+
+  page_handler_->RequestClosePage();
+  return false;
 }
 
 void CrostiniInstallerUI::ClickInstallForTesting() {
@@ -200,12 +213,12 @@
       std::move(pending_page_handler), std::move(pending_page),
       // Using Unretained(this) because |page_handler_| will not out-live
       // |this|.
-      base::BindOnce(&CrostiniInstallerUI::OnWebUICloseDialog,
+      base::BindOnce(&CrostiniInstallerUI::OnPageClosed,
                      base::Unretained(this)));
 }
 
-void CrostiniInstallerUI::OnWebUICloseDialog() {
-  can_close_ = true;
+void CrostiniInstallerUI::OnPageClosed() {
+  page_closed_ = true;
   // CloseDialog() is a no-op if we are not in a dialog (e.g. user
   // access the page using the URL directly, which is not supported).
   ui::MojoWebDialogUI::CloseDialog(nullptr);
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.h b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.h
index 8f4fee5f..de78f42 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.h
+++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.h
@@ -24,7 +24,10 @@
   explicit CrostiniInstallerUI(content::WebUI* web_ui);
   ~CrostiniInstallerUI() override;
 
-  bool can_close();
+  // Send a close request to the web page. Return true if the page is already
+  // closed.
+  bool RequestClosePage();
+
   void ClickInstallForTesting();
 
   // Instantiates implementor of the mojom::PageHandlerFactory
@@ -41,12 +44,12 @@
       mojo::PendingReceiver<chromeos::crostini_installer::mojom::PageHandler>
           pending_page_handler) override;
 
-  void OnWebUICloseDialog();
+  void OnPageClosed();
 
   std::unique_ptr<CrostiniInstallerPageHandler> page_handler_;
   mojo::Receiver<chromeos::crostini_installer::mojom::PageHandlerFactory>
       page_factory_receiver_{this};
-  bool can_close_ = false;
+  bool page_closed_ = false;
 
   WEB_UI_CONTROLLER_TYPE_DECL();
 
diff --git a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader.mojom b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader.mojom
index 7f01682..94cf4da 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader.mojom
+++ b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader.mojom
@@ -42,10 +42,15 @@
   CancelBeforeStart();
   // If an upgrade fails, the user may choose to restore a container backup.
   Restore();
-  // The page normally is displayed in a dialog. Call this to close the dialog.
-  // chrome.send('dialogClose') should not be used, which could kill the page
-  // handler before previous mojom calls have been run.
-  Close();
+  // This is called when the web page is "closed", and the dialog (or whatever)
+  // hosting it should also be closed. This can happen as a result of
+  // Page::RequestClose() being called, or it can happen spontaneously (e.g.
+  // user clicking cancel on the page or installation finished).
+  //
+  // Note that the web page should not use something like
+  // chrome.send('dialogClose'), which could kill the page handler before
+  // previous mojom calls have been run.
+  OnPageClosed();
   // Close the dialog and launch the Terminal or other app after a successful
   // upgrade.
   Launch();
@@ -81,4 +86,7 @@
   // After user cancels the upgrade, this is called when the cancellation
   // finishes.
   OnCanceled();
+  // Informs the page that it should be closed. The page should respond with
+  // PageHandler::OnPageClosed() to indicate it is ready to be closed.
+  RequestClose();
 };
diff --git a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_dialog.cc b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_dialog.cc
index 31603e1..12143c2 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_dialog.cc
+++ b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_dialog.cc
@@ -83,7 +83,14 @@
     return true;
   }
   // Disallow closing without WebUI consent.
-  return upgrader_ui_ == nullptr || upgrader_ui_->can_close();
+  //
+  // Note that while the function name |CanCloseDialog| does not indicate the
+  // intend to close the dialog, but it is indeed only called when we are
+  // closing it, so requesting closing the page here is appropriate. One might
+  // think we should actually do all of this in |OnDialogCloseRequested|
+  // instead, but unfortunately that function is called after the web content is
+  // closed.
+  return upgrader_ui_ == nullptr || upgrader_ui_->RequestClosePage();
 }
 
 namespace {
diff --git a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_page_handler.cc b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_page_handler.cc
index 8d783cf..f0051c6 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_page_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_page_handler.cc
@@ -22,13 +22,13 @@
     mojo::PendingReceiver<chromeos::crostini_upgrader::mojom::PageHandler>
         pending_page_handler,
     mojo::PendingRemote<chromeos::crostini_upgrader::mojom::Page> pending_page,
-    base::OnceClosure close_dialog_callback,
+    base::OnceClosure on_page_closed,
     base::OnceCallback<void(bool)> launch_callback)
     : web_contents_{web_contents},
       upgrader_ui_delegate_{upgrader_ui_delegate},
       receiver_{this, std::move(pending_page_handler)},
       page_{std::move(pending_page)},
-      close_dialog_callback_{std::move(close_dialog_callback)},
+      on_page_closed_{std::move(on_page_closed)},
       launch_callback_{std::move(launch_callback)} {
   upgrader_ui_delegate_->AddObserver(this);
 }
@@ -49,6 +49,11 @@
   Redisplay();
 }
 
+// Send a close request to the web page.
+void CrostiniUpgraderPageHandler::RequestClosePage() {
+  page_->RequestClose();
+}
+
 void CrostiniUpgraderPageHandler::Backup(bool show_file_chooser) {
   Redisplay();
   base::UmaHistogramEnumeration(crostini::kUpgradeDialogEventHistogram,
@@ -95,12 +100,12 @@
   }
 }
 
-void CrostiniUpgraderPageHandler::Close() {
+void CrostiniUpgraderPageHandler::OnPageClosed() {
   if (launch_callback_) {
     Launch();
   }
-  if (close_dialog_callback_) {
-    std::move(close_dialog_callback_).Run();
+  if (on_page_closed_) {
+    std::move(on_page_closed_).Run();
   }
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_page_handler.h b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_page_handler.h
index edf98821..01c0ac7 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_page_handler.h
+++ b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_page_handler.h
@@ -32,10 +32,13 @@
           pending_page_handler,
       mojo::PendingRemote<chromeos::crostini_upgrader::mojom::Page>
           pending_page,
-      base::OnceClosure close_dialog_callback,
+      base::OnceClosure on_page_closed,
       base::OnceCallback<void(bool)> launch_callback);
   ~CrostiniUpgraderPageHandler() override;
 
+  // Send a close request to the web page.
+  void RequestClosePage();
+
   // chromeos::crostini_upgrader::mojom::PageHandler:
   void Backup(bool show_file_chooser) override;
   void StartPrechecks() override;
@@ -43,7 +46,7 @@
   void Restore() override;
   void Cancel() override;
   void CancelBeforeStart() override;
-  void Close() override;
+  void OnPageClosed() override;
   void Launch() override;
 
   // CrostiniUpgraderUIObserver
@@ -68,7 +71,7 @@
   crostini::CrostiniUpgraderUIDelegate* upgrader_ui_delegate_;  // Not owned.
   mojo::Receiver<chromeos::crostini_upgrader::mojom::PageHandler> receiver_;
   mojo::Remote<chromeos::crostini_upgrader::mojom::Page> page_;
-  base::OnceClosure close_dialog_callback_;
+  base::OnceClosure on_page_closed_;
   base::OnceCallback<void(bool)> launch_callback_;
   // Will we need to restart the container as part of launch_callback?
   // |restart_required_| is true unless the user cancels before starting the
diff --git a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.cc b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.cc
index 8d195a2..842ec62 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.cc
@@ -122,6 +122,15 @@
 
 CrostiniUpgraderUI::~CrostiniUpgraderUI() = default;
 
+bool CrostiniUpgraderUI::RequestClosePage() {
+  if (page_closed_ || !page_handler_) {
+    return true;
+  }
+
+  page_handler_->RequestClosePage();
+  return false;
+}
+
 void CrostiniUpgraderUI::BindInterface(
     mojo::PendingReceiver<
         chromeos::crostini_upgrader::mojom::PageHandlerFactory>
@@ -145,13 +154,12 @@
       std::move(pending_page_handler), std::move(pending_page),
       // Using Unretained(this) because |page_handler_| will not out-live
       // |this|.
-      base::BindOnce(&CrostiniUpgraderUI::OnWebUICloseDialog,
-                     base::Unretained(this)),
+      base::BindOnce(&CrostiniUpgraderUI::OnPageClosed, base::Unretained(this)),
       std::move(launch_callback_));
 }
 
-void CrostiniUpgraderUI::OnWebUICloseDialog() {
-  can_close_ = true;
+void CrostiniUpgraderUI::OnPageClosed() {
+  page_closed_ = true;
   // CloseDialog() is a no-op if we are not in a dialog (e.g. user
   // access the page using the URL directly, which is not supported).
   ui::MojoWebDialogUI::CloseDialog(nullptr);
diff --git a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.h b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.h
index 6126283..13c5605 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.h
+++ b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.h
@@ -27,7 +27,10 @@
   explicit CrostiniUpgraderUI(content::WebUI* web_ui);
   ~CrostiniUpgraderUI() override;
 
-  bool can_close() { return can_close_; }
+  // Send a close request to the web page. Return true if the page is already
+  // closed.
+  bool RequestClosePage();
+
   void set_launch_callback(base::OnceCallback<void(bool)>(launch_callback)) {
     launch_callback_ = std::move(launch_callback);
   }
@@ -47,7 +50,7 @@
       mojo::PendingReceiver<chromeos::crostini_upgrader::mojom::PageHandler>
           pending_page_handler) override;
 
-  void OnWebUICloseDialog();
+  void OnPageClosed();
 
   std::unique_ptr<CrostiniUpgraderPageHandler> page_handler_;
   mojo::Receiver<chromeos::crostini_upgrader::mojom::PageHandlerFactory>
@@ -56,7 +59,7 @@
   // Not owned. Passed to |page_handler_|
   base::OnceCallback<void(bool)> launch_callback_;
 
-  bool can_close_ = false;
+  bool page_closed_ = false;
 
   WEB_UI_CONTROLLER_TYPE_DECL();
 
diff --git a/chrome/browser/ui/webui/chromeos/login/debug/debug_overlay_handler.cc b/chrome/browser/ui/webui/chromeos/login/debug/debug_overlay_handler.cc
index 1520461..5548ccd 100644
--- a/chrome/browser/ui/webui/chromeos/login/debug/debug_overlay_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/debug/debug_overlay_handler.cc
@@ -12,6 +12,9 @@
 #include "base/files/file_util.h"
 #include "base/path_service.h"
 #include "base/system/sys_info.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
 #include "base/time/time.h"
 #include "chrome/common/chrome_paths.h"
 #include "chromeos/constants/chromeos_switches.h"
@@ -44,9 +47,10 @@
     const base::FilePath& screenshot_dir,
     const std::string& screenshot_name,
     scoped_refptr<base::RefCountedMemory> png_data) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(&StoreScreenshot, screenshot_dir,
-                                screenshot_name, png_data));
+  base::ThreadPool::PostTask(
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
+      base::BindOnce(&StoreScreenshot, screenshot_dir, screenshot_name,
+                     png_data));
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.cc
index 8d99eb5..634b08c 100644
--- a/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h"
 
+#include "base/metrics/histogram_functions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -207,19 +208,19 @@
 void SyncConsentScreenHandler::HandleAcceptAndContinue(
     const login::StringList& consent_description,
     const std::string& consent_confirmation) {
-  Continue(consent_description, consent_confirmation, /*enable_sync=*/true);
+  Continue(consent_description, consent_confirmation, UserChoice::kAccepted);
 }
 
 void SyncConsentScreenHandler::HandleDeclineAndContinue(
     const login::StringList& consent_description,
     const std::string& consent_confirmation) {
-  Continue(consent_description, consent_confirmation, /*enable_sync=*/false);
+  Continue(consent_description, consent_confirmation, UserChoice::kDeclined);
 }
 
 void SyncConsentScreenHandler::Continue(
     const login::StringList& consent_description,
     const std::string& consent_confirmation,
-    bool enable_sync) {
+    UserChoice choice) {
   DCHECK(chromeos::features::IsSplitSettingsSyncEnabled());
   std::vector<int> consent_description_ids;
   int consent_confirmation_id;
@@ -228,8 +229,7 @@
   // Manually add this ID because the string contains a runtime substitution,
   // so it's not included in GetConsentIDs().
   consent_description_ids.push_back(IDS_LOGIN_SYNC_CONSENT_SCREEN_SUBTITLE);
-  screen_->OnAcceptAndContinue(consent_description_ids, consent_confirmation_id,
-                               enable_sync);
+  screen_->OnContinue(consent_description_ids, consent_confirmation_id, choice);
 
   SyncConsentScreen::SyncConsentScreenTestDelegate* test_delegate =
       screen_->GetDelegateForTesting();
diff --git a/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h
index dfb8a054..a11e554 100644
--- a/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h
@@ -42,6 +42,10 @@
  public:
   using TView = SyncConsentScreenView;
 
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused. Public for testing.
+  enum class UserChoice { kDeclined = 0, kAccepted = 1, kMaxValue = kAccepted };
+
   explicit SyncConsentScreenHandler(JSCallsContainer* js_calls_container);
   ~SyncConsentScreenHandler() override;
 
@@ -77,7 +81,7 @@
   // Helper for the accept and decline cases.
   void Continue(const ::login::StringList& consent_description,
                 const std::string& consent_confirmation,
-                bool enable_sync);
+                UserChoice choice);
 
   // Adds resource |resource_id| both to |builder| and to |known_string_ids_|.
   void RememberLocalizedValue(const std::string& name,
diff --git a/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom b/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom
index 9d0c643..bb37cc5 100644
--- a/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom
+++ b/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom
@@ -31,7 +31,7 @@
   kCellularProxy = 20,
   kCellularAutoConnectToNetwork = 21,
   kInstantTetheringOnOff = 22,
-  kDisconnectTetherNetwork = 22,
+  kDisconnectTetherNetwork = 23,
 
   // Bluetooth section.
   kBluetoothOnOff = 100,
@@ -118,6 +118,7 @@
   kAssistantOkGoogle = 604,
   kAssistantNotifications = 605,
   kAssistantVoiceInput = 606,
+  kTrainAssistantVoiceModel = 607,
 
   // Apps section.
   kManageAndroidPreferences = 700,
diff --git a/chrome/browser/ui/webui/settings/chromeos/internet_section.cc b/chrome/browser/ui/webui/settings/chromeos/internet_section.cc
index 1b06d0d5..2e6e18d7 100644
--- a/chrome/browser/ui/webui/settings/chromeos/internet_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/internet_section.cc
@@ -413,6 +413,13 @@
   return *settings;
 }
 
+const std::vector<mojom::Setting>& GetTetherDetailsSettings() {
+  static const base::NoDestructor<std::vector<mojom::Setting>> settings({
+      mojom::Setting::kDisconnectTetherNetwork,
+  });
+  return *settings;
+}
+
 bool IsConnected(network_config::mojom::ConnectionStateType connection_state) {
   return connection_state ==
              network_config::mojom::ConnectionStateType::kOnline ||
@@ -440,6 +447,8 @@
           return base::Contains(GetWifiDetailsSettings(), setting);
         case mojom::Subpage::kCellularDetails:
           return base::Contains(GetCellularDetailsSettings(), setting);
+        case mojom::Subpage::kTetherDetails:
+          return base::Contains(GetTetherDetailsSettings(), setting);
         default:
           return false;
       }
@@ -702,8 +711,12 @@
                                      mojom::SearchResultIcon::kCellular,
                                      mojom::SearchResultDefaultRank::kMedium,
                                      mojom::kMobileDataNetworksSubpagePath);
-  generator->RegisterNestedSetting(mojom::Setting::kMobileOnOff,
-                                   mojom::Subpage::kMobileDataNetworks);
+  static constexpr mojom::Setting kMobileDataNetworksSettings[] = {
+      mojom::Setting::kMobileOnOff,
+      mojom::Setting::kInstantTetheringOnOff,
+  };
+  RegisterNestedSettingBulk(mojom::Subpage::kMobileDataNetworks,
+                            kMobileDataNetworksSettings, generator);
   generator->RegisterTopLevelAltSetting(mojom::Setting::kMobileOnOff);
 
   // Cellular details. Cellular details are considered a child of the mobile
@@ -726,8 +739,8 @@
       mojom::SearchResultIcon::kInstantTethering,
       mojom::SearchResultDefaultRank::kMedium,
       mojom::kTetherDetailsSubpagePath);
-  generator->RegisterNestedSetting(mojom::Setting::kInstantTetheringOnOff,
-                                   mojom::Subpage::kMobileDataNetworks);
+  RegisterNestedSettingBulk(mojom::Subpage::kTetherDetails,
+                            GetTetherDetailsSettings(), generator);
 
   // VPN.
   generator->RegisterTopLevelSubpage(
diff --git a/chrome/browser/ui/webui/settings/chromeos/search/search_handler.cc b/chrome/browser/ui/webui/settings/chromeos/search/search_handler.cc
index f6252753..80d2e0e 100644
--- a/chrome/browser/ui/webui/settings/chromeos/search/search_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/search/search_handler.cc
@@ -296,7 +296,7 @@
   // declared before kSetting, so follow the same pattern from default ranks
   // above. Note that if the types are equal, this will return false, which
   // induces a strict weak ordering.
-  return static_cast<int32_t>(first->type) - static_cast<int32_t>(second->type);
+  return static_cast<int32_t>(first->type) < static_cast<int32_t>(second->type);
 }
 
 }  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/chromeos/search/search_handler.h b/chrome/browser/ui/webui/settings/chromeos/search/search_handler.h
index 6809e3c7..9cbd7cb6 100644
--- a/chrome/browser/ui/webui/settings/chromeos/search/search_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/search/search_handler.h
@@ -61,7 +61,7 @@
               SearchCallback callback) override;
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(SearchHandlerTest, CompareIdenticalResults);
+  FRIEND_TEST_ALL_PREFIXES(SearchHandlerTest, CompareSearchResults);
 
   std::vector<mojom::SearchResultPtr> GenerateSearchResultsArray(
       const std::vector<local_search_service::Result>&
diff --git a/chrome/browser/ui/webui/settings/chromeos/search/search_handler_unittest.cc b/chrome/browser/ui/webui/settings/chromeos/search/search_handler_unittest.cc
index 2b46118..fd88417 100644
--- a/chrome/browser/ui/webui/settings/chromeos/search/search_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/search/search_handler_unittest.cc
@@ -228,7 +228,7 @@
 }
 
 // Regression test for https://crbug.com/1090184.
-TEST_F(SearchHandlerTest, CompareIdenticalResults) {
+TEST_F(SearchHandlerTest, CompareSearchResults) {
   // Create two equal dummy results.
   mojom::SearchResultPtr a = CreateDummyResult();
   mojom::SearchResultPtr b = CreateDummyResult();
@@ -237,6 +237,36 @@
   // should return false regardless of the order of parameters.
   EXPECT_FALSE(SearchHandler::CompareSearchResults(a, b));
   EXPECT_FALSE(SearchHandler::CompareSearchResults(b, a));
+
+  // Differ only on default rank.
+  a = CreateDummyResult();
+  a->default_rank = mojom::SearchResultDefaultRank::kLow;
+  b = CreateDummyResult();
+  b->default_rank = mojom::SearchResultDefaultRank::kHigh;
+
+  // Comparison value should differ.
+  EXPECT_NE(SearchHandler::CompareSearchResults(b, a),
+            SearchHandler::CompareSearchResults(a, b));
+
+  // Differ only on relevance score.
+  a = CreateDummyResult();
+  a->relevance_score = 0;
+  b = CreateDummyResult();
+  b->relevance_score = 1;
+
+  // Comparison value should differ.
+  EXPECT_NE(SearchHandler::CompareSearchResults(b, a),
+            SearchHandler::CompareSearchResults(a, b));
+
+  // Differ only on type.
+  a = CreateDummyResult();
+  a->type = mojom::SearchResultType::kSection;
+  b = CreateDummyResult();
+  b->type = mojom::SearchResultType::kSubpage;
+
+  // Comparison value should differ.
+  EXPECT_NE(SearchHandler::CompareSearchResults(b, a),
+            SearchHandler::CompareSearchResults(a, b));
 }
 
 }  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/chromeos/search_section.cc b/chrome/browser/ui/webui/settings/chromeos/search_section.cc
index 0517d80..d79d18b 100644
--- a/chrome/browser/ui/webui/settings/chromeos/search_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/search_section.cc
@@ -51,27 +51,12 @@
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSubpage,
        {.subpage = mojom::Subpage::kAssistant}},
-      {IDS_OS_SETTINGS_TAG_ASSISTANT_QUICK_ANSWERS,
-       mojom::kAssistantSubpagePath,
-       mojom::SearchResultIcon::kAssistant,
-       mojom::SearchResultDefaultRank::kMedium,
-       mojom::SearchResultType::kSetting,
-       {.setting = mojom::Setting::kAssistantQuickAnswers}},
       {IDS_OS_SETTINGS_TAG_ASSISTANT_PREFERRED_INPUT,
        mojom::kAssistantSubpagePath,
        mojom::SearchResultIcon::kAssistant,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
        {.setting = mojom::Setting::kAssistantVoiceInput}},
-      {IDS_OS_SETTINGS_TAG_ASSISTANT_OK_GOOGLE,
-       mojom::kAssistantSubpagePath,
-       mojom::SearchResultIcon::kAssistant,
-       mojom::SearchResultDefaultRank::kMedium,
-       mojom::SearchResultType::kSetting,
-       {.setting = mojom::Setting::kAssistantOkGoogle},
-       {IDS_OS_SETTINGS_TAG_ASSISTANT_OK_GOOGLE_ALT1,
-        IDS_OS_SETTINGS_TAG_ASSISTANT_OK_GOOGLE_ALT2,
-        SearchConcept::kAltTagEnd}},
       {IDS_OS_SETTINGS_TAG_ASSISTANT_NOTIFICATIONS,
        mojom::kAssistantSubpagePath,
        mojom::SearchResultIcon::kAssistant,
@@ -117,21 +102,39 @@
 
 const std::vector<SearchConcept>& GetAssistantQuickAnswersSearchConcepts() {
   static const base::NoDestructor<std::vector<SearchConcept>> tags({
-      // TODO(khorimoto): Add "Assistant Quick Answers" search concepts.
+      {IDS_OS_SETTINGS_TAG_ASSISTANT_QUICK_ANSWERS,
+       mojom::kAssistantSubpagePath,
+       mojom::SearchResultIcon::kAssistant,
+       mojom::SearchResultDefaultRank::kMedium,
+       mojom::SearchResultType::kSetting,
+       {.setting = mojom::Setting::kAssistantQuickAnswers}},
   });
   return *tags;
 }
 
 const std::vector<SearchConcept>& GetAssistantHotwordDspSearchConcepts() {
   static const base::NoDestructor<std::vector<SearchConcept>> tags({
-      // TODO(khorimoto): Add "Assistant hotword DSP" search concepts.
+      {IDS_OS_SETTINGS_TAG_ASSISTANT_OK_GOOGLE,
+       mojom::kAssistantSubpagePath,
+       mojom::SearchResultIcon::kAssistant,
+       mojom::SearchResultDefaultRank::kMedium,
+       mojom::SearchResultType::kSetting,
+       {.setting = mojom::Setting::kAssistantOkGoogle},
+       {IDS_OS_SETTINGS_TAG_ASSISTANT_OK_GOOGLE_ALT1,
+        IDS_OS_SETTINGS_TAG_ASSISTANT_OK_GOOGLE_ALT2,
+        SearchConcept::kAltTagEnd}},
   });
   return *tags;
 }
 
 const std::vector<SearchConcept>& GetAssistantVoiceMatchSearchConcepts() {
   static const base::NoDestructor<std::vector<SearchConcept>> tags({
-      // TODO(khorimoto): Add "Assistant hotword DSP" search concepts.
+      {IDS_OS_SETTINGS_TAG_ASSISTANT_TRAIN_VOICE_MODEL,
+       mojom::kAssistantSubpagePath,
+       mojom::SearchResultIcon::kAssistant,
+       mojom::SearchResultDefaultRank::kMedium,
+       mojom::SearchResultType::kSetting,
+       {.setting = mojom::Setting::kTrainAssistantVoiceModel}},
   });
   return *tags;
 }
@@ -280,6 +283,7 @@
       mojom::Setting::kAssistantOkGoogle,
       mojom::Setting::kAssistantNotifications,
       mojom::Setting::kAssistantVoiceInput,
+      mojom::Setting::kTrainAssistantVoiceModel,
   };
   RegisterNestedSettingBulk(mojom::Subpage::kAssistant, kAssistantSettings,
                             generator);
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index f0ac00d..e27a689 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -905,8 +905,12 @@
       {"noExceptionsFound", IDS_SETTINGS_PASSWORDS_EXCEPTIONS_NONE},
       {"import", IDS_PASSWORD_MANAGER_IMPORT_BUTTON},
       {"exportMenuItem", IDS_SETTINGS_PASSWORDS_EXPORT_MENU_ITEM},
+      {"optInAccountStorageBody",
+       IDS_SETTINGS_PASSWORDS_OPT_IN_ACCOUNT_STORAGE_BODY},
       {"optInAccountStorageLabel",
        IDS_SETTINGS_PASSWORDS_OPT_IN_ACCOUNT_STORAGE_LABEL},
+      {"optOutAccountStorageBody",
+       IDS_SETTINGS_PASSWORDS_OPT_OUT_ACCOUNT_STORAGE_BODY},
       {"optOutAccountStorageLabel",
        IDS_SETTINGS_PASSWORDS_OPT_OUT_ACCOUNT_STORAGE_LABEL},
       {"undoRemovePassword", IDS_SETTINGS_PASSWORD_UNDO},
@@ -1314,6 +1318,10 @@
        IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_PRIMARY_LABEL},
       {"safetyCheckExtensionsButtonAriaLabel",
        IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BUTTON_ARIA_LABEL},
+      {"safetyCheckChromeCleanerPrimaryLabel",
+       IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_PRIMARY_LABEL},
+      {"safetyCheckChromeCleanerButtonAriaLabel",
+       IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_BUTTON_ARIA_LABEL},
   };
   AddLocalizedStringsBulk(html_source, kLocalizedStrings);
 
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index 9b6537e6..9e29823 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -285,6 +285,12 @@
       "syncSetupFriendlySettings",
       base::FeatureList::IsEnabled(features::kSyncSetupFriendlySettings));
 
+#if defined(OS_WIN)
+  html_source->AddBoolean(
+      "safetyCheckChromeCleanerChildEnabled",
+      base::FeatureList::IsEnabled(features::kSafetyCheckChromeCleanerChild));
+#endif
+
 #if defined(OS_CHROMEOS)
   html_source->AddBoolean("splitSettingsSyncEnabled",
                           chromeos::features::IsSplitSettingsSyncEnabled());
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index 3704ff4..fa8a808 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -320,7 +320,6 @@
 # vr_ui must not depend on vr_common.
 component("vr_base") {
   sources = [
-    "assets_component_update_status.h",
     "assets_load_status.h",
     "assets_loader.cc",
     "assets_loader.h",
@@ -337,9 +336,6 @@
     "keyboard_delegate.h",
     "keyboard_ui_interface.h",
     "macros.h",
-    "metrics/metrics_helper.cc",
-    "metrics/metrics_helper.h",
-    "mode.h",
     "model/assets.cc",
     "model/assets.h",
     "model/camera_model.h",
diff --git a/chrome/browser/vr/assets_component_update_status.h b/chrome/browser/vr/assets_component_update_status.h
deleted file mode 100644
index cb11cc4b..0000000
--- a/chrome/browser/vr/assets_component_update_status.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2017 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_VR_ASSETS_COMPONENT_UPDATE_STATUS_H_
-#define CHROME_BROWSER_VR_ASSETS_COMPONENT_UPDATE_STATUS_H_
-
-namespace vr {
-
-// Status of the assets component after an update.
-//
-// Keep this enum aligned with VRAssetsComponentUpdateStatus in
-// //tools/metrics/histograms/enums.xml.
-// If you rename this file update the
-// reference in
-// //tools/metrics/histograms/histograms.xml.
-enum class AssetsComponentUpdateStatus : int {
-  kSuccess = 0,       // Component was installed successfully.
-  kInvalid = 1,       // Failed to verify component.
-  kIncompatible = 2,  // Component version is not compatible with Chrome.
-};
-
-}  // namespace vr
-
-#endif  // CHROME_BROWSER_VR_ASSETS_COMPONENT_UPDATE_STATUS_H_
diff --git a/chrome/browser/vr/assets_load_status.h b/chrome/browser/vr/assets_load_status.h
index 20683b0..2b9e2a8d 100644
--- a/chrome/browser/vr/assets_load_status.h
+++ b/chrome/browser/vr/assets_load_status.h
@@ -8,12 +8,6 @@
 namespace vr {
 
 // Status of loading assets.
-//
-// Keep this enum aligned with VRAssetsLoadStatus in
-// //tools/metrics/histograms/enums.xml.
-// If you rename this file update the
-// reference in
-// //tools/metrics/histograms/histograms.xml.
 enum class AssetsLoadStatus : int {
   kSuccess = 0,       // Assets loaded successfully.
   kParseFailure = 1,  // Failed to load assets.
diff --git a/chrome/browser/vr/assets_loader.cc b/chrome/browser/vr/assets_loader.cc
index 8cc36f2..1a05d4e 100644
--- a/chrome/browser/vr/assets_loader.cc
+++ b/chrome/browser/vr/assets_loader.cc
@@ -12,7 +12,6 @@
 #include "base/task/thread_pool.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
-#include "chrome/browser/vr/metrics/metrics_helper.h"
 #include "chrome/browser/vr/model/assets.h"
 #include "chrome/browser/vr/vr_buildflags.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -97,19 +96,6 @@
                                 std::move(on_loaded)));
 }
 
-MetricsHelper* AssetsLoader::GetMetricsHelper() {
-  // If we instantiate metrics_helper_ in the constructor all functions of
-  // MetricsHelper must be called in a valid sequence from the thread the
-  // constructor ran on. However, the assets class can be instantiated from any
-  // thread. To avoid the aforementioned restriction, create metrics_helper_ the
-  // first time it is used and, thus, give the caller control over when the
-  // sequence starts.
-  if (!metrics_helper_) {
-    metrics_helper_ = std::make_unique<MetricsHelper>();
-  }
-  return metrics_helper_.get();
-}
-
 bool AssetsLoader::ComponentReady() {
   DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
   return component_ready_;
@@ -259,7 +245,6 @@
   if (on_component_ready_callback_) {
     on_component_ready_callback_.Run();
   }
-  GetMetricsHelper()->OnComponentReady(version);
 }
 
 void AssetsLoader::LoadInternal(
diff --git a/chrome/browser/vr/assets_loader.h b/chrome/browser/vr/assets_loader.h
index 9069c5c..6832512 100644
--- a/chrome/browser/vr/assets_loader.h
+++ b/chrome/browser/vr/assets_loader.h
@@ -29,7 +29,6 @@
 // set of features.
 constexpr uint32_t kMinMajorVrAssetsComponentVersion = 1;
 
-class MetricsHelper;
 struct AssetsLoaderSingletonTrait;
 struct Assets;
 
@@ -64,8 +63,6 @@
   // when calling this function.
   void Load(OnAssetsLoadedCallback on_loaded);
 
-  MetricsHelper* GetMetricsHelper();
-
   // Returns true if the component is ready.
   // Must be called on the main thread.
   bool ComponentReady();
@@ -93,7 +90,6 @@
   base::Version component_version_;
   base::FilePath component_install_dir_;
   scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
-  std::unique_ptr<MetricsHelper> metrics_helper_;
   OnComponentReadyCallback on_component_ready_callback_;
 
   base::WeakPtrFactory<AssetsLoader> weak_ptr_factory_{this};
diff --git a/chrome/browser/vr/metrics/metrics_helper.cc b/chrome/browser/vr/metrics/metrics_helper.cc
deleted file mode 100644
index 98bffdb..0000000
--- a/chrome/browser/vr/metrics/metrics_helper.cc
+++ /dev/null
@@ -1,217 +0,0 @@
-// Copyright 2017 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/vr/metrics/metrics_helper.h"
-
-#include "base/metrics/histogram_functions.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/version.h"
-#include "net/base/network_change_notifier.h"
-
-namespace vr {
-
-namespace {
-
-constexpr char kStatusVr[] = "VR.Component.Assets.Status.OnEnter.AllVR";
-constexpr char kStatusVrBrowsing[] =
-    "VR.Component.Assets.Status.OnEnter.VRBrowsing";
-constexpr char kStatusWebVr[] =
-    "VR.Component.Assets.Status.OnEnter.WebVRPresentation";
-constexpr char kLatencyVrBrowsing[] =
-    "VR.Component.Assets.DurationUntilReady.OnEnter.VRBrowsing";
-constexpr char kLatencyWebVr[] =
-    "VR.Component.Assets.DurationUntilReady.OnEnter.WebVRPresentation";
-constexpr char kLatencyRegisterComponent[] =
-    "VR.Component.Assets.DurationUntilReady.OnRegisterComponent";
-// TODO(tiborg): Rename VRAssetsComponentStatus and VRAssetsLoadStatus in
-// enums.xml and consider merging them.
-constexpr char kComponentUpdateStatus[] =
-    "VR.Component.Assets.VersionAndStatus.OnUpdate";
-constexpr char kAssetsLoadStatus[] =
-    "VR.Component.Assets.VersionAndStatus.OnLoad";
-constexpr char kNetworkConnectionTypeRegisterComponent[] =
-    "VR.NetworkConnectionType.OnRegisterComponent";
-constexpr char kNetworkConnectionTypeVr[] =
-    "VR.NetworkConnectionType.OnEnter.AllVR";
-constexpr char kNetworkConnectionTypeVrBrowsing[] =
-    "VR.NetworkConnectionType.OnEnter.VRBrowsing";
-constexpr char kNetworkConnectionTypeWebVr[] =
-    "VR.NetworkConnectionType.OnEnter.WebVRPresentation";
-
-const auto kMinLatency = base::TimeDelta::FromMilliseconds(500);
-const auto kMaxLatency = base::TimeDelta::FromHours(1);
-constexpr size_t kLatencyBucketCount = 100;
-
-// Ensure that this stays in sync with VRComponentStatus in enums.xml.
-enum class ComponentStatus : int {
-  kReady = 0,
-  kUnreadyOther = 1,
-
-  // This must be last.
-  kCount,
-};
-
-void LogStatus(Mode mode, ComponentStatus status) {
-  switch (mode) {
-    case Mode::kVr:
-      UMA_HISTOGRAM_ENUMERATION(kStatusVr, status, ComponentStatus::kCount);
-      return;
-    case Mode::kVrBrowsing:
-      UMA_HISTOGRAM_ENUMERATION(kStatusVrBrowsing, status,
-                                ComponentStatus::kCount);
-      return;
-    case Mode::kWebXrVrPresentation:
-      UMA_HISTOGRAM_ENUMERATION(kStatusWebVr, status, ComponentStatus::kCount);
-      return;
-    default:
-      NOTIMPLEMENTED();
-      return;
-  }
-}
-
-void LogLatency(Mode mode, const base::TimeDelta& latency) {
-  switch (mode) {
-    case Mode::kVrBrowsing:
-      UMA_HISTOGRAM_CUSTOM_TIMES(kLatencyVrBrowsing, latency, kMinLatency,
-                                 kMaxLatency, kLatencyBucketCount);
-      return;
-    case Mode::kWebXrVrPresentation:
-      UMA_HISTOGRAM_CUSTOM_TIMES(kLatencyWebVr, latency, kMinLatency,
-                                 kMaxLatency, kLatencyBucketCount);
-      return;
-    default:
-      NOTIMPLEMENTED();
-      return;
-  }
-}
-
-void LogConnectionType(Mode mode,
-                       net::NetworkChangeNotifier::ConnectionType type) {
-  switch (mode) {
-    case Mode::kVr:
-      UMA_HISTOGRAM_ENUMERATION(
-          kNetworkConnectionTypeVr, type,
-          net::NetworkChangeNotifier::ConnectionType::CONNECTION_LAST + 1);
-      return;
-    case Mode::kVrBrowsing:
-      UMA_HISTOGRAM_ENUMERATION(
-          kNetworkConnectionTypeVrBrowsing, type,
-          net::NetworkChangeNotifier::ConnectionType::CONNECTION_LAST + 1);
-      return;
-    case Mode::kWebXrVrPresentation:
-      UMA_HISTOGRAM_ENUMERATION(
-          kNetworkConnectionTypeWebVr, type,
-          net::NetworkChangeNotifier::ConnectionType::CONNECTION_LAST + 1);
-      return;
-    default:
-      NOTIMPLEMENTED();
-      return;
-  }
-}
-
-uint32_t EncodeVersionStatus(const base::Optional<base::Version>& version,
-                             int status) {
-  if (!version) {
-    // Component version 0.0 is invalid. Thus, use it for when version is not
-    // available.
-    return status;
-  }
-  return version->components()[0] * 1000 * 1000 +
-         version->components()[1] * 1000 + status;
-}
-
-}  // namespace
-
-MetricsHelper::MetricsHelper() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-MetricsHelper::~MetricsHelper() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-void MetricsHelper::OnComponentReady(const base::Version& version) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  component_ready_ = true;
-  auto now = base::TimeTicks::Now();
-  LogLatencyIfWaited(Mode::kVrBrowsing, now);
-  LogLatencyIfWaited(Mode::kWebXrVrPresentation, now);
-  OnComponentUpdated(AssetsComponentUpdateStatus::kSuccess, version);
-
-  if (!logged_ready_duration_on_component_register_) {
-    DCHECK(component_register_time_);
-    auto ready_duration = now - *component_register_time_;
-    UMA_HISTOGRAM_CUSTOM_TIMES(kLatencyRegisterComponent, ready_duration,
-                               kMinLatency, kMaxLatency, kLatencyBucketCount);
-    logged_ready_duration_on_component_register_ = true;
-  }
-}
-
-void MetricsHelper::OnEnter(Mode mode) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  LogConnectionType(mode, net::NetworkChangeNotifier::GetConnectionType());
-  auto& enter_time = GetEnterTime(mode);
-  if (enter_time) {
-    // While we are stopping the time between entering and component readiness
-    // we pretend the user is waiting on the block screen. Do not report further
-    // UMA metrics.
-    return;
-  }
-  LogStatus(mode, component_ready_ ? ComponentStatus::kReady
-                                   : ComponentStatus::kUnreadyOther);
-  if (!component_ready_) {
-    enter_time = base::TimeTicks::Now();
-  }
-}
-
-void MetricsHelper::OnRegisteredComponent() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  UMA_HISTOGRAM_ENUMERATION(
-      kNetworkConnectionTypeRegisterComponent,
-      net::NetworkChangeNotifier::GetConnectionType(),
-      net::NetworkChangeNotifier::ConnectionType::CONNECTION_LAST + 1);
-  DCHECK(!component_register_time_);
-  component_register_time_ = base::TimeTicks::Now();
-}
-
-void MetricsHelper::OnComponentUpdated(
-    AssetsComponentUpdateStatus status,
-    const base::Optional<base::Version>& version) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::UmaHistogramSparse(
-      kComponentUpdateStatus,
-      EncodeVersionStatus(version, static_cast<int>(status)));
-}
-
-void MetricsHelper::OnAssetsLoaded(AssetsLoadStatus status,
-                                   const base::Version& component_version) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::UmaHistogramSparse(
-      kAssetsLoadStatus,
-      EncodeVersionStatus(component_version, static_cast<int>(status)));
-}
-
-base::Optional<base::TimeTicks>& MetricsHelper::GetEnterTime(Mode mode) {
-  switch (mode) {
-    case Mode::kVr:
-      return enter_vr_time_;
-    case Mode::kVrBrowsing:
-      return enter_vr_browsing_time_;
-    case Mode::kWebXrVrPresentation:
-      return enter_web_vr_time_;
-    default:
-      NOTIMPLEMENTED();
-      return enter_vr_time_;
-  }
-}
-
-void MetricsHelper::LogLatencyIfWaited(Mode mode, const base::TimeTicks& now) {
-  auto& enter_time = GetEnterTime(mode);
-  if (enter_time) {
-    LogLatency(mode, now - *enter_time);
-    enter_time = base::nullopt;
-  }
-}
-
-}  // namespace vr
diff --git a/chrome/browser/vr/metrics/metrics_helper.h b/chrome/browser/vr/metrics/metrics_helper.h
deleted file mode 100644
index d1ade64..0000000
--- a/chrome/browser/vr/metrics/metrics_helper.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2017 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_VR_METRICS_METRICS_HELPER_H_
-#define CHROME_BROWSER_VR_METRICS_METRICS_HELPER_H_
-
-#include <string>
-
-#include "base/optional.h"
-#include "base/sequence_checker.h"
-#include "base/time/time.h"
-#include "chrome/browser/vr/assets_component_update_status.h"
-#include "chrome/browser/vr/assets_load_status.h"
-#include "chrome/browser/vr/mode.h"
-#include "chrome/browser/vr/vr_base_export.h"
-
-namespace base {
-class Version;
-}  // namespace base
-
-namespace vr {
-
-// Helper to collect VR UMA metrics.
-//
-// For thread-safety, all functions must be called in sequence.
-class VR_BASE_EXPORT MetricsHelper {
- public:
-  MetricsHelper();
-  ~MetricsHelper();
-
-  void OnComponentReady(const base::Version& version);
-  void OnEnter(Mode mode);
-  void OnRegisteredComponent();
-  void OnComponentUpdated(AssetsComponentUpdateStatus status,
-                          const base::Optional<base::Version>& version);
-  void OnAssetsLoaded(AssetsLoadStatus status,
-                      const base::Version& component_version);
-
- private:
-  base::Optional<base::TimeTicks>& GetEnterTime(Mode mode);
-  void LogLatencyIfWaited(Mode mode, const base::TimeTicks& now);
-
-  base::Optional<base::TimeTicks> enter_vr_time_;
-  base::Optional<base::TimeTicks> enter_vr_browsing_time_;
-  base::Optional<base::TimeTicks> enter_web_vr_time_;
-  base::Optional<base::TimeTicks> component_register_time_;
-  bool logged_ready_duration_on_component_register_ = false;
-  bool component_ready_ = false;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-};
-
-}  // namespace vr
-
-#endif  // CHROME_BROWSER_VR_METRICS_METRICS_HELPER_H_
diff --git a/chrome/browser/vr/mode.h b/chrome/browser/vr/mode.h
deleted file mode 100644
index 5c805e2..0000000
--- a/chrome/browser/vr/mode.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2017 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_VR_MODE_H_
-#define CHROME_BROWSER_VR_MODE_H_
-
-namespace vr {
-
-// Specifies one of Chrome's VR modes.
-// TODO(ymalik): These modes are currently only used for VR metrics. We should
-// use model/ui_modes.h instead.
-enum class Mode : int {
-  kNoVr,
-  kVr,          // All modes in VR.
-  kVrBrowsing,  // Both kVrBrowsingRegular and kVrBrowsingFullscreen.
-  kVrBrowsingRegular,
-  kVrBrowsingFullscreen,  // Cinema mode.
-  kWebXrVrPresentation,
-};
-
-}  // namespace vr
-
-#endif  // CHROME_BROWSER_VR_MODE_H_
diff --git a/chrome/browser/vr/speech_recognizer.cc b/chrome/browser/vr/speech_recognizer.cc
index c6893e61a..f44d077c 100644
--- a/chrome/browser/vr/speech_recognizer.cc
+++ b/chrome/browser/vr/speech_recognizer.cc
@@ -7,7 +7,6 @@
 #include <memory>
 
 #include "base/bind.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/vr/browser_ui_interface.h"
 #include "chrome/grit/generated_resources.h"
@@ -34,8 +33,6 @@
 // Invalid speech session.
 const int kInvalidSessionId = -1;
 
-const char kSearchEndStateUmaName[] = "VR.VoiceSearch.EndState";
-
 static content::SpeechRecognitionManager* g_manager_for_test = nullptr;
 
 content::SpeechRecognitionManager* GetSpeechRecognitionManager() {
@@ -345,8 +342,6 @@
                      base::Unretained(speech_recognizer_on_io_.get())));
   if (ui_) {
     ui_->SetSpeechRecognitionEnabled(false);
-    UMA_HISTOGRAM_ENUMERATION(kSearchEndStateUmaName, VOICE_SEARCH_CANCEL,
-                              COUNT);
   }
 }
 
@@ -380,14 +375,10 @@
     case SPEECH_RECOGNITION_TRY_AGAIN:
       ui_->SetRecognitionResult(
           l10n_util::GetStringUTF16(IDS_VR_NO_SPEECH_RECOGNITION_RESULT));
-      UMA_HISTOGRAM_ENUMERATION(kSearchEndStateUmaName, VOICE_SEARCH_TRY_AGAIN,
-                                COUNT);
       break;
     case SPEECH_RECOGNITION_END:
       if (!final_result_.empty()) {
         ui_->SetRecognitionResult(final_result_);
-        UMA_HISTOGRAM_ENUMERATION(kSearchEndStateUmaName,
-                                  VOICE_SEARCH_OPEN_SEARCH_PAGE, COUNT);
         if (delegate_)
           delegate_->OnVoiceResults(final_result_);
       }
diff --git a/chrome/browser/vr/speech_recognizer.h b/chrome/browser/vr/speech_recognizer.h
index fb6cc06..80f5020b 100644
--- a/chrome/browser/vr/speech_recognizer.h
+++ b/chrome/browser/vr/speech_recognizer.h
@@ -50,14 +50,6 @@
   SPEECH_RECOGNITION_NETWORK_ERROR,
 };
 
-// These enums are used for histogram. Do NOT renumber or delete these enums.
-enum VoiceSearchEndState {
-  VOICE_SEARCH_OPEN_SEARCH_PAGE = 0,
-  VOICE_SEARCH_CANCEL = 1,
-  VOICE_SEARCH_TRY_AGAIN = 2,
-  COUNT,
-};
-
 class VoiceResultDelegate {
  public:
   virtual ~VoiceResultDelegate() {}
diff --git a/chrome/browser/vr/ui_suppressed_element.h b/chrome/browser/vr/ui_suppressed_element.h
index f4e5cd4d..33e01ed80 100644
--- a/chrome/browser/vr/ui_suppressed_element.h
+++ b/chrome/browser/vr/ui_suppressed_element.h
@@ -7,11 +7,8 @@
 
 namespace vr {
 
-// When adding values, insert them before kCount and add them to
-// VRSuppressedElement in enums.xml. Do not reuse values.
-// Also, remove kPlaceholderForPreviousHighValue.
-// When values become obsolete, comment them out here and mark them deprecated
-// in enums.xml.
+// When adding values, insert them before kCount, do not reuse values, and also
+// remove kPlaceholderForPreviousHighValue.
 enum class UiSuppressedElement : int {
   kFileChooser = 0,
   kBluetoothChooser = 1,
diff --git a/chrome/browser/vr/ui_unsupported_mode.h b/chrome/browser/vr/ui_unsupported_mode.h
index 9994a5a2..ac4f09b5 100644
--- a/chrome/browser/vr/ui_unsupported_mode.h
+++ b/chrome/browser/vr/ui_unsupported_mode.h
@@ -7,9 +7,6 @@
 
 namespace vr {
 
-// Ensure that this stays in sync with VRUnsupportedMode in enums.xml
-// These values are written to logs.  New enum values can be added, but existing
-// enums must never be renumbered or deleted and reused.
 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.vr
 enum class UiUnsupportedMode : int {
   kUnhandledCodePoint = 0,
diff --git a/chrome/browser/vr/vr_tab_helper.cc b/chrome/browser/vr/vr_tab_helper.cc
index 715a1a1..3e2af7bf 100644
--- a/chrome/browser/vr/vr_tab_helper.cc
+++ b/chrome/browser/vr/vr_tab_helper.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/vr/vr_tab_helper.h"
 
-#include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/xr_runtime_manager.h"
@@ -111,7 +110,6 @@
   if (!IsInVr(contents))
     return false;
 
-  bool suppress = false;
   switch (element) {
     // The following are suppressed if in VR.
     case UiSuppressedElement::kHttpAuth:
@@ -131,19 +129,12 @@
     // suppression.
     case UiSuppressedElement::kFileAccessPermission:
     case UiSuppressedElement::kContextMenu:
-      suppress = true;
-      break;
+      return true;
     case UiSuppressedElement::kPlaceholderForPreviousHighValue:
     case UiSuppressedElement::kCount:
-      suppress = false;
       NOTREACHED();
-      break;
+      return false;
   }
-  if (suppress) {
-    UMA_HISTOGRAM_ENUMERATION("VR.Shell.EncounteredSuppressedUI", element,
-                              UiSuppressedElement::kCount);
-  }
-  return suppress;
 }
 
 WEB_CONTENTS_USER_DATA_KEY_IMPL(VrTabHelper)
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index 64a1127..03c17d3 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -251,6 +251,7 @@
     ":web_applications_test_support",
     "//chrome/app:command_ids",
     "//chrome/browser/web_applications/components",
+    "//chrome/browser/web_applications/extensions",
     "//chrome/test:test_support",
     "//chrome/test:test_support_ui",
     "//components/permissions:permissions",
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index 1ef11da..7af3d35b 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -53,6 +53,8 @@
     "web_app_provider_base.h",
     "web_app_provider_base_factory.cc",
     "web_app_provider_base_factory.h",
+    "web_app_run_on_os_login.cc",
+    "web_app_run_on_os_login.h",
     "web_app_shortcut.cc",
     "web_app_shortcut.h",
     "web_app_shortcuts_menu.cc",
@@ -104,6 +106,7 @@
     sources += [
       "web_app_file_handler_registration_win.cc",
       "web_app_file_handler_registration_win.h",
+      "web_app_run_on_os_login_win.cc",
       "web_app_shortcut_win.cc",
       "web_app_shortcut_win.h",
       "web_app_shortcuts_menu_win.cc",
@@ -162,7 +165,10 @@
   ]
 
   if (is_win) {
-    sources += [ "web_app_file_handler_registration_win_unittest.cc" ]
+    sources += [
+      "web_app_file_handler_registration_win_unittest.cc",
+      "web_app_run_on_os_login_win_unittest.cc",
+    ]
   }
 
   if (is_mac) {
diff --git a/chrome/browser/web_applications/components/app_shortcut_manager.cc b/chrome/browser/web_applications/components/app_shortcut_manager.cc
index 87e9fb2..097113b 100644
--- a/chrome/browser/web_applications/components/app_shortcut_manager.cc
+++ b/chrome/browser/web_applications/components/app_shortcut_manager.cc
@@ -12,6 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/web_applications/components/web_app_run_on_os_login.h"
 #include "chrome/common/chrome_features.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -228,7 +229,7 @@
 void AppShortcutManager::OnShortcutInfoRetrievedRegisterRunOnOsLogin(
     RegisterRunOnOsLoginCallback callback,
     std::unique_ptr<ShortcutInfo> info) {
-  internals::ScheduleRegisterRunOnOsLogin(std::move(info), std::move(callback));
+  ScheduleRegisterRunOnOsLogin(std::move(info), std::move(callback));
 }
 
 void AppShortcutManager::OnShortcutInfoRetrievedUpdateShortcuts(
diff --git a/chrome/browser/web_applications/components/app_shortcut_manager.h b/chrome/browser/web_applications/components/app_shortcut_manager.h
index 60895c8b..fd7b8c81 100644
--- a/chrome/browser/web_applications/components/app_shortcut_manager.h
+++ b/chrome/browser/web_applications/components/app_shortcut_manager.h
@@ -16,6 +16,7 @@
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/app_registrar_observer.h"
 #include "chrome/browser/web_applications/components/web_app_id.h"
+#include "chrome/browser/web_applications/components/web_app_run_on_os_login.h"
 #include "chrome/browser/web_applications/components/web_app_shortcut.h"
 #include "chrome/browser/web_applications/components/web_app_shortcuts_menu.h"
 #include "chrome/common/web_application_info.h"
diff --git a/chrome/browser/web_applications/components/web_app_run_on_os_login.cc b/chrome/browser/web_applications/components/web_app_run_on_os_login.cc
new file mode 100644
index 0000000..b18f20c7
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_run_on_os_login.cc
@@ -0,0 +1,59 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/components/web_app_run_on_os_login.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "build/build_config.h"
+#include "chrome/browser/web_applications/components/web_app_shortcut.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+namespace web_app {
+
+namespace {
+
+void RegisterRunOnOsLoginAndPostCallback(RegisterRunOnOsLoginCallback callback,
+                                         const ShortcutInfo& shortcut_info) {
+  bool run_on_os_login_registered =
+      internals::RegisterRunOnOsLogin(shortcut_info);
+  content::GetUIThreadTaskRunner({})->PostTask(
+      FROM_HERE,
+      base::BindOnce(std::move(callback), run_on_os_login_registered));
+}
+
+}  // namespace
+
+namespace internals {
+
+#if !defined(OS_WIN)
+// TODO(crbug.com/897302): This boilerplate function is used for platforms
+// other than Windows, currently the feature is only supported in Windows.
+bool RegisterRunOnOsLogin(const ShortcutInfo& shortcut_info) {
+  return false;
+}
+
+// TODO(crbug.com/897302): This boilerplate function is used for platforms
+// other than Windows, currently the feature is only supported in Windows.
+void UnregisterRunOnOsLogin(const base::FilePath& profile_path,
+                            const base::string16& shortcut_title) {}
+#endif
+
+}  // namespace internals
+
+void ScheduleRegisterRunOnOsLogin(std::unique_ptr<ShortcutInfo> shortcut_info,
+                                  RegisterRunOnOsLoginCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  internals::PostShortcutIOTask(
+      base::BindOnce(&RegisterRunOnOsLoginAndPostCallback, std::move(callback)),
+      std::move(shortcut_info));
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/components/web_app_run_on_os_login.h b/chrome/browser/web_applications/components/web_app_run_on_os_login.h
new file mode 100644
index 0000000..e91425a
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_run_on_os_login.h
@@ -0,0 +1,51 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_RUN_ON_OS_LOGIN_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_RUN_ON_OS_LOGIN_H_
+
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "base/strings/string16.h"
+#include "chrome/browser/web_applications/components/web_app_id.h"
+#include "chrome/browser/web_applications/components/web_app_shortcut.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace web_app {
+
+struct ShortcutInfo;
+
+// Callback made when RegisterRunOnOsLogin has finished trying to register the
+// app to the OS Startup indicating whether or not it was successfully
+// registered.
+using RegisterRunOnOsLoginCallback = base::OnceCallback<void(bool success)>;
+
+namespace internals {
+
+// Registers the app with the OS to run on OS login. Platform specific
+// implementations are required for this.
+// See web_app_shortcut_win.cc for Windows.
+bool RegisterRunOnOsLogin(const ShortcutInfo& shortcut_info);
+
+// Unregisters the app with the OS from running on startup. Platform specific
+// implementations are required for this.
+// See web_app_shortcut_win.cc for Windows.
+void UnregisterRunOnOsLogin(const base::FilePath& profile_path,
+                            const base::string16& shortcut_title);
+
+}  // namespace internals
+
+// Schedules a call to |RegisterRunOnOsLogin| on the Shortcut IO thread and
+// invokes |callback| when complete. This function must be called from the UI
+// thread.
+void ScheduleRegisterRunOnOsLogin(std::unique_ptr<ShortcutInfo> shortcut_info,
+                                  RegisterRunOnOsLoginCallback callback);
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_RUN_ON_OS_LOGIN_H_
diff --git a/chrome/browser/web_applications/components/web_app_run_on_os_login_win.cc b/chrome/browser/web_applications/components/web_app_run_on_os_login_win.cc
new file mode 100644
index 0000000..53afc14a7
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_run_on_os_login_win.cc
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/components/web_app_run_on_os_login.h"
+
+#include <memory>
+
+#include "base/files/file_util.h"
+#include "chrome/browser/web_applications/components/web_app_shortcut.h"
+#include "chrome/browser/web_applications/components/web_app_shortcut_win.h"
+
+namespace web_app {
+
+namespace internals {
+
+bool RegisterRunOnOsLogin(const ShortcutInfo& shortcut_info) {
+  base::FilePath shortcut_data_dir = GetShortcutDataDir(shortcut_info);
+
+  ShortcutLocations locations;
+  locations.in_startup = true;
+
+  return CreatePlatformShortcuts(shortcut_data_dir, locations,
+                                 SHORTCUT_CREATION_BY_USER, shortcut_info);
+}
+
+void UnregisterRunOnOsLogin(const base::FilePath& profile_path,
+                            const base::string16& shortcut_title) {
+  web_app::ShortcutLocations all_shortcut_locations;
+  all_shortcut_locations.in_startup = true;
+  std::vector<base::FilePath> all_paths =
+      GetShortcutPaths(all_shortcut_locations);
+
+  // Only Startup folder is the expected path to be returned in all_paths.
+  for (const auto& path : all_paths) {
+    // Find all app's shortcuts in Startup folder to delete.
+    std::vector<base::FilePath> shortcut_files =
+        FindAppShortcutsByProfileAndTitle(path, profile_path, shortcut_title);
+    for (const auto& shortcut_file : shortcut_files) {
+      base::DeleteFile(shortcut_file, /*recursive=*/false);
+    }
+  }
+}
+
+}  // namespace internals
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/components/web_app_run_on_os_login_win_unittest.cc b/chrome/browser/web_applications/components/web_app_run_on_os_login_win_unittest.cc
new file mode 100644
index 0000000..87539ed
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_run_on_os_login_win_unittest.cc
@@ -0,0 +1,96 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/components/web_app_run_on_os_login.h"
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/web_applications/components/web_app_shortcut.h"
+#include "chrome/browser/web_applications/components/web_app_shortcut_win.h"
+#include "chrome/browser/web_applications/test/web_app_test.h"
+#include "chrome/common/web_application_info.h"
+#include "chrome/installer/util/shell_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace web_app {
+
+namespace {
+
+constexpr char kAppTitle[] = {"app"};
+}  // namespace
+
+class WebAppRunOnOsLoginWinTest : public WebAppTest {
+ public:
+  void TearDown() override {
+    base::FilePath location = GetStartupFolder();
+    std::vector<base::FilePath> shortcuts = GetShortcuts();
+    for (const auto& shortcut_file : shortcuts) {
+      base::DeleteFile(shortcut_file, /*recursive=*/false);
+    }
+    WebAppTest::TearDown();
+  }
+
+  std::unique_ptr<ShortcutInfo> GetShortcutInfo() {
+    auto shortcut_info = std::make_unique<ShortcutInfo>();
+    shortcut_info->extension_id = "app-id";
+    shortcut_info->title = base::UTF8ToUTF16(kAppTitle);
+    shortcut_info->profile_path = profile()->GetPath();
+
+    gfx::ImageFamily image_family;
+    SquareSizePx icon_size_in_px = GetDesiredIconSizesForShortcut().back();
+    gfx::ImageSkia image_skia = CreateDefaultApplicationIcon(icon_size_in_px);
+    image_family.Add(gfx::Image(image_skia));
+    shortcut_info->favicon = std::move(image_family);
+
+    return shortcut_info;
+  }
+
+  base::FilePath GetStartupFolder() {
+    base::FilePath location;
+    ShellUtil::GetShortcutPath(
+        ShellUtil::ShortcutLocation::SHORTCUT_LOCATION_STARTUP,
+        ShellUtil::ShellChange::CURRENT_USER, &location);
+    return location;
+  }
+
+  std::vector<base::FilePath> GetShortcuts() {
+    return internals::FindAppShortcutsByProfileAndTitle(
+        GetStartupFolder(), profile()->GetPath(), base::UTF8ToUTF16(kAppTitle));
+  }
+
+  void VerifyShortcutCreated() {
+    std::vector<base::FilePath> shortcuts = GetShortcuts();
+    EXPECT_GT(shortcuts.size(), 0u);
+  }
+
+  void VerifyShortcutDeleted() {
+    std::vector<base::FilePath> shortcuts = GetShortcuts();
+    EXPECT_EQ(shortcuts.size(), 0u);
+  }
+};
+
+TEST_F(WebAppRunOnOsLoginWinTest, Register) {
+  std::unique_ptr<ShortcutInfo> shortcut_info = GetShortcutInfo();
+  bool result = internals::RegisterRunOnOsLogin(*shortcut_info);
+  EXPECT_TRUE(result);
+  VerifyShortcutCreated();
+}
+
+TEST_F(WebAppRunOnOsLoginWinTest, Unregister) {
+  std::unique_ptr<ShortcutInfo> shortcut_info = GetShortcutInfo();
+  bool result = internals::RegisterRunOnOsLogin(*shortcut_info);
+  EXPECT_TRUE(result);
+  VerifyShortcutCreated();
+
+  internals::UnregisterRunOnOsLogin(profile()->GetPath(),
+                                    base::UTF8ToUTF16(kAppTitle));
+  VerifyShortcutDeleted();
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/components/web_app_shortcut.cc b/chrome/browser/web_applications/components/web_app_shortcut.cc
index 9cd64a1b..284bdcd5 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut.cc
+++ b/chrome/browser/web_applications/components/web_app_shortcut.cc
@@ -71,15 +71,6 @@
       FROM_HERE, base::BindOnce(std::move(callback), shortcut_created));
 }
 
-void RegisterRunOnOsLoginAndPostCallback(RegisterRunOnOsLoginCallback callback,
-                                         const ShortcutInfo& shortcut_info) {
-  bool run_on_os_login_registered =
-      internals::RegisterRunOnOsLogin(shortcut_info);
-  content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE,
-      base::BindOnce(std::move(callback), run_on_os_login_registered));
-}
-
 }  // namespace
 
 ShortcutInfo::ShortcutInfo() = default;
@@ -175,28 +166,6 @@
                      std::move(shortcut_info));
 }
 
-void ScheduleRegisterRunOnOsLogin(std::unique_ptr<ShortcutInfo> shortcut_info,
-                                  RegisterRunOnOsLoginCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  PostShortcutIOTask(
-      base::BindOnce(&RegisterRunOnOsLoginAndPostCallback, std::move(callback)),
-      std::move(shortcut_info));
-}
-
-#if !defined(OS_WIN)
-// TODO(crbug.com/897302): This boilerplate function is used for platforms
-// other than Windows, currently the feature is only supported in Windows.
-bool RegisterRunOnOsLogin(const ShortcutInfo& shortcut_info) {
-  return false;
-}
-
-// TODO(crbug.com/897302): This boilerplate function is used for platforms
-// other than Windows, currently the feature is only supported in Windows.
-void UnregisterRunOnOsLogin(const base::FilePath& profile_path,
-                            const base::string16& shortcut_title) {}
-#endif
-
 void PostShortcutIOTaskAndReply(
     base::OnceCallback<void(const ShortcutInfo&)> task,
     std::unique_ptr<ShortcutInfo> shortcut_info,
diff --git a/chrome/browser/web_applications/components/web_app_shortcut.h b/chrome/browser/web_applications/components/web_app_shortcut.h
index 4c3fc3a..74693de 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut.h
+++ b/chrome/browser/web_applications/components/web_app_shortcut.h
@@ -124,12 +124,6 @@
 // created.
 using CreateShortcutsCallback = base::OnceCallback<void(bool shortcut_created)>;
 
-// Callback made when RegisterRunOnOsLogin has finished trying to register the
-// app to the OS Startup indicating whether or not it was successfully
-// registered.
-using RegisterRunOnOsLoginCallback =
-    base::OnceCallback<void(bool registered_successfully)>;
-
 // Returns an array of desired icon sizes (in px) to be contained in an app OS
 // shortcut, sorted in ascending order (biggest desired icon size is last).
 base::span<const int> GetDesiredIconSizesForShortcut();
@@ -161,23 +155,6 @@
     std::unique_ptr<ShortcutInfo> shortcut_info,
     CreateShortcutsCallback callback);
 
-// Schedules a call to |RegisterRunOnOsLogin| on the Shortcut IO thread and
-// invokes |callback| when complete. This function must be called from the UI
-// thread.
-void ScheduleRegisterRunOnOsLogin(std::unique_ptr<ShortcutInfo> shortcut_info,
-                                  RegisterRunOnOsLoginCallback callback);
-
-// Registers the app with the OS to run on OS login. Platform specific
-// implementations are required for this.
-// See web_app_shortcut_win.cc for Windows.
-bool RegisterRunOnOsLogin(const ShortcutInfo& shortcut_info);
-
-// Unregisters the app with the OS from running on startup. Platform specific
-// implementations are required for this.
-// See web_app_shortcut_win.cc for Windows.
-void UnregisterRunOnOsLogin(const base::FilePath& profile_path,
-                            const base::string16& shortcut_title);
-
 // Delete all the shortcuts we have added for this extension. This is the
 // platform specific implementation of the DeleteAllShortcuts function, and
 // is executed on the FILE thread.
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_win.cc b/chrome/browser/web_applications/components/web_app_shortcut_win.cc
index f2d68d3b..44a98c9 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut_win.cc
+++ b/chrome/browser/web_applications/components/web_app_shortcut_win.cc
@@ -123,50 +123,6 @@
   return false;
 }
 
-// Finds shortcuts in |shortcut_path| that match profile for |profile_path| and
-// extension with title |shortcut_name|.
-// If |shortcut_name| is empty, finds all shortcuts matching |profile_path|.
-std::vector<base::FilePath> FindAppShortcutsByProfileAndTitle(
-    const base::FilePath& shortcut_path,
-    const base::FilePath& profile_path,
-    const base::string16& shortcut_name) {
-  std::vector<base::FilePath> shortcut_paths;
-
-  if (shortcut_name.empty()) {
-    // Find all shortcuts for this profile.
-    base::FileEnumerator files(shortcut_path, false,
-                               base::FileEnumerator::FILES,
-                               FILE_PATH_LITERAL("*.lnk"));
-    base::FilePath shortcut_file = files.Next();
-    while (!shortcut_file.empty()) {
-      if (IsAppShortcutForProfile(shortcut_file, profile_path))
-        shortcut_paths.push_back(shortcut_file);
-      shortcut_file = files.Next();
-    }
-  } else {
-    // Find all shortcuts matching |shortcut_name|.
-    base::FilePath base_path =
-        shortcut_path
-            .Append(web_app::internals::GetSanitizedFileName(shortcut_name))
-            .AddExtension(FILE_PATH_LITERAL(".lnk"));
-
-    const int fileNamesToCheck = 10;
-    for (int i = 0; i < fileNamesToCheck; ++i) {
-      base::FilePath shortcut_file = base_path;
-      if (i > 0) {
-        shortcut_file = shortcut_file.InsertBeforeExtensionASCII(
-            base::StringPrintf(" (%d)", i));
-      }
-      if (base::PathExists(shortcut_file) &&
-          IsAppShortcutForProfile(shortcut_file, profile_path)) {
-        shortcut_paths.push_back(shortcut_file);
-      }
-    }
-  }
-
-  return shortcut_paths;
-}
-
 // Creates application shortcuts in a given set of paths.
 // |shortcut_paths| is a list of directories in which shortcuts should be
 // created. If |creation_reason| is SHORTCUT_CREATION_AUTOMATED and there is an
@@ -222,9 +178,9 @@
     if (creation_reason == web_app::SHORTCUT_CREATION_AUTOMATED) {
       // Check whether there is an existing shortcut to this app.
       std::vector<base::FilePath> shortcut_files =
-          FindAppShortcutsByProfileAndTitle(shortcut_paths[i],
-                                            shortcut_info.profile_path,
-                                            shortcut_info.title);
+          web_app::internals::FindAppShortcutsByProfileAndTitle(
+              shortcut_paths[i], shortcut_info.profile_path,
+              shortcut_info.title);
       if (!shortcut_files.empty())
         continue;
     }
@@ -298,8 +254,8 @@
     base::FilePath taskbar_pin_path;
     if (base::PathService::Get(base::DIR_TASKBAR_PINS, &taskbar_pin_path)) {
       std::vector<base::FilePath> taskbar_pin_files =
-          FindAppShortcutsByProfileAndTitle(taskbar_pin_path, profile_path,
-                                            title);
+          web_app::internals::FindAppShortcutsByProfileAndTitle(
+              taskbar_pin_path, profile_path, title);
       *was_pinned_to_taskbar = !taskbar_pin_files.empty();
     } else {
       *was_pinned_to_taskbar = false;
@@ -309,7 +265,8 @@
   for (std::vector<base::FilePath>::const_iterator i = all_paths.begin();
        i != all_paths.end(); ++i) {
     std::vector<base::FilePath> shortcut_files =
-        FindAppShortcutsByProfileAndTitle(*i, profile_path, title);
+        web_app::internals::FindAppShortcutsByProfileAndTitle(*i, profile_path,
+                                                              title);
     if (shortcut_paths && !shortcut_files.empty()) {
       shortcut_paths->push_back(*i);
     }
@@ -353,6 +310,47 @@
 
 namespace internals {
 
+std::vector<base::FilePath> FindAppShortcutsByProfileAndTitle(
+    const base::FilePath& shortcut_path,
+    const base::FilePath& profile_path,
+    const base::string16& shortcut_name) {
+  std::vector<base::FilePath> shortcut_paths;
+
+  if (shortcut_name.empty()) {
+    // Find all shortcuts for this profile.
+    base::FileEnumerator files(shortcut_path, false,
+                               base::FileEnumerator::FILES,
+                               FILE_PATH_LITERAL("*.lnk"));
+    base::FilePath shortcut_file = files.Next();
+    while (!shortcut_file.empty()) {
+      if (IsAppShortcutForProfile(shortcut_file, profile_path))
+        shortcut_paths.push_back(shortcut_file);
+      shortcut_file = files.Next();
+    }
+  } else {
+    // Find all shortcuts matching |shortcut_name|.
+    base::FilePath base_path =
+        shortcut_path
+            .Append(web_app::internals::GetSanitizedFileName(shortcut_name))
+            .AddExtension(FILE_PATH_LITERAL(".lnk"));
+
+    const int fileNamesToCheck = 10;
+    for (int i = 0; i < fileNamesToCheck; ++i) {
+      base::FilePath shortcut_file = base_path;
+      if (i > 0) {
+        shortcut_file = shortcut_file.InsertBeforeExtensionASCII(
+            base::StringPrintf(" (%d)", i));
+      }
+      if (base::PathExists(shortcut_file) &&
+          IsAppShortcutForProfile(shortcut_file, profile_path)) {
+        shortcut_paths.push_back(shortcut_file);
+      }
+    }
+  }
+
+  return shortcut_paths;
+}
+
 void OnShortcutInfoLoadedForSetRelaunchDetails(
     HWND hwnd,
     std::unique_ptr<ShortcutInfo> shortcut_info) {
@@ -393,35 +391,6 @@
   return true;
 }
 
-bool RegisterRunOnOsLogin(const ShortcutInfo& shortcut_info) {
-  base::FilePath shortcut_data_dir =
-      internals::GetShortcutDataDir(shortcut_info);
-
-  ShortcutLocations locations;
-  locations.in_startup = true;
-
-  return CreatePlatformShortcuts(shortcut_data_dir, locations,
-                                 SHORTCUT_CREATION_BY_USER, shortcut_info);
-}
-
-void UnregisterRunOnOsLogin(const base::FilePath& profile_path,
-                            const base::string16& shortcut_title) {
-  web_app::ShortcutLocations all_shortcut_locations;
-  all_shortcut_locations.in_startup = true;
-  std::vector<base::FilePath> all_paths =
-      web_app::internals::GetShortcutPaths(all_shortcut_locations);
-
-  // Only Startup folder is the expected path to be returned in all_paths.
-  for (const auto& path : all_paths) {
-    // Find all app's shortcuts in Startup folder to delete.
-    std::vector<base::FilePath> shortcut_files =
-        FindAppShortcutsByProfileAndTitle(path, profile_path, shortcut_title);
-    for (const auto& shortcut_file : shortcut_files) {
-      base::DeleteFile(shortcut_file, /*recursive=*/false);
-    }
-  }
-}
-
 bool CreatePlatformShortcuts(const base::FilePath& web_app_path,
                              const ShortcutLocations& creation_locations,
                              ShortcutCreationReason creation_reason,
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_win.h b/chrome/browser/web_applications/components/web_app_shortcut_win.h
index 88b2e1f2..0c50c71 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut_win.h
+++ b/chrome/browser/web_applications/components/web_app_shortcut_win.h
@@ -31,6 +31,14 @@
                       const gfx::ImageFamily& image,
                       bool refresh_shell_icon_cache);
 
+// Finds shortcuts in |shortcut_path| that match profile for |profile_path| and
+// extension with title |shortcut_name|.
+// If |shortcut_name| is empty, finds all shortcuts matching |profile_path|.
+std::vector<base::FilePath> FindAppShortcutsByProfileAndTitle(
+    const base::FilePath& shortcut_path,
+    const base::FilePath& profile_path,
+    const base::string16& shortcut_name);
+
 base::FilePath GetIconFilePath(const base::FilePath& web_app_path,
                                const base::string16& title);
 
diff --git a/chrome/browser/web_applications/manifest_update_manager_browsertest.cc b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
index 80ab92df..78882398 100644
--- a/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
+++ b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
@@ -8,12 +8,14 @@
 #include <vector>
 
 #include "base/bind_helpers.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/strings/string_util.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/time/time.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/installable/installable_metrics.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/web_applications/components/app_icon_manager.h"
@@ -24,6 +26,7 @@
 #include "chrome/browser/web_applications/components/pending_app_manager.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
+#include "chrome/browser/web_applications/extensions/bookmark_app_registrar.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/browser/web_applications/test/test_system_web_app_installation.h"
 #include "chrome/browser/web_applications/test/web_app_install_observer.h"
@@ -33,6 +36,8 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/url_loader_interceptor.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/test_extension_registry_observer.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -893,6 +898,54 @@
   EXPECT_EQ(GetProvider().registrar().GetAppThemeColor(app_id), SK_ColorGREEN);
 }
 
+using ManifestUpdateManagerWebAppsBrowserTest =
+    ManifestUpdateManagerBrowserTest;
+
+IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerWebAppsBrowserTest,
+                       CheckFindsThemeColorChangeForShadowBookmarkApp) {
+  auto* extensions_registry =
+      extensions::ExtensionRegistry::Get(browser()->profile());
+  extensions::TestExtensionRegistryObserver extensions_registry_observer(
+      extensions_registry);
+
+  extensions::BookmarkAppRegistrar bookmark_app_registrar{browser()->profile()};
+
+  constexpr char kManifestTemplate[] = R"(
+    {
+      "name": "Test app name",
+      "start_url": ".",
+      "scope": "/",
+      "display": "standalone",
+      "icons": $1,
+      "theme_color": "$2"
+    }
+  )";
+  OverrideManifest(kManifestTemplate, {kInstallableIconList, "blue"});
+  AppId app_id = InstallWebApp();
+  EXPECT_EQ(GetProvider().registrar().GetAppThemeColor(app_id), SK_ColorBLUE);
+
+  scoped_refptr<const extensions::Extension> extension =
+      extensions_registry_observer.WaitForExtensionInstalled();
+  EXPECT_EQ(extension->id(), app_id);
+  EXPECT_EQ(bookmark_app_registrar.GetAppThemeColor(app_id).value(),
+            SK_ColorBLUE);
+
+  OverrideManifest(kManifestTemplate, {kInstallableIconList, "red"});
+  EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
+            ManifestUpdateResult::kAppUpdated);
+  AwaitShortcutsUpdated(kInstallableIconTopLeftColor);
+  EXPECT_EQ(GetProvider().registrar().GetAppThemeColor(app_id), SK_ColorRED);
+
+  // Wait for all update events sequentially. Otherwise the test is flaky.
+  extensions_registry_observer.WaitForExtensionUnloaded();
+  extensions_registry_observer.WaitForExtensionLoaded();
+  extension = extensions_registry_observer.WaitForExtensionReady();
+
+  EXPECT_EQ(extension->id(), app_id);
+  EXPECT_EQ(bookmark_app_registrar.GetAppThemeColor(app_id).value(),
+            SK_ColorRED);
+}
+
 INSTANTIATE_TEST_SUITE_P(All,
                          ManifestUpdateManagerBrowserTest,
                          ::testing::Values(ProviderType::kBookmarkApps,
@@ -905,4 +958,9 @@
                                            ProviderType::kWebApps),
                          ProviderTypeParamToString);
 
+INSTANTIATE_TEST_SUITE_P(All,
+                         ManifestUpdateManagerWebAppsBrowserTest,
+                         ::testing::Values(ProviderType::kWebApps),
+                         ProviderTypeParamToString);
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc
index 79df85e..9e8707b 100644
--- a/chrome/browser/web_applications/web_app_install_finalizer.cc
+++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -184,6 +184,7 @@
   web_app->SetAdditionalSearchTerms(web_app_info.additional_search_terms);
   web_app->AddSource(source);
   web_app->SetIsInSyncInstall(false);
+  const bool is_synced = web_app->IsSynced();
 
   UpdateIntWebAppPref(profile_->GetPrefs(), app_id, kLatestWebAppInstallSource,
                       static_cast<int>(options.install_source));
@@ -208,7 +209,7 @@
   // We should install shadow bookmark app only for kSync source (we sync only
   // user-installed apps). System, Policy, WebAppStore, Default apps should not
   // get a shadow bookmark app.
-  if (legacy_finalizer_ && source == Source::kSync) {
+  if (legacy_finalizer_ && is_synced) {
     legacy_finalizer_->FinalizeInstall(web_app_info, options,
                                        base::DoNothing());
   }
@@ -326,6 +327,7 @@
   const WebApp* app = GetWebAppRegistrar().GetAppById(app_id);
   DCHECK(app);
   DCHECK(app->CanUserUninstallExternalApp());
+  const bool is_synced = app->IsSynced();
 
   if (app->IsDefaultApp()) {
     UpdateBoolWebAppPref(profile_->GetPrefs(), app_id,
@@ -342,7 +344,7 @@
   UninstallWebApp(app_id, std::move(callback));
 
   // Uninstall shadow bookmark app from this device and from the sync server.
-  if (legacy_finalizer_)
+  if (legacy_finalizer_ && is_synced)
     legacy_finalizer_->UninstallExternalAppByUser(app_id, base::DoNothing());
 }
 
@@ -370,6 +372,7 @@
 
   // Prepare copy-on-write to update existing app.
   auto web_app = std::make_unique<WebApp>(*existing_web_app);
+  const bool is_synced = web_app->IsSynced();
 
   CommitCallback commit_callback = base::BindOnce(
       &WebAppInstallFinalizer::OnDatabaseCommitCompletedForUpdate,
@@ -379,7 +382,8 @@
   SetWebAppManifestFieldsAndWriteData(web_app_info, std::move(web_app),
                                       std::move(commit_callback));
 
-  // TODO(crbug.com/1020037): Update shadow bookmark app in extensions.
+  if (legacy_finalizer_ && is_synced)
+    legacy_finalizer_->FinalizeUpdate(web_app_info, base::DoNothing());
 }
 
 void WebAppInstallFinalizer::Start() {
diff --git a/chrome/common/apps/platform_apps/api/PRESUBMIT.py b/chrome/common/apps/platform_apps/api/PRESUBMIT.py
new file mode 100644
index 0000000..28bc319
--- /dev/null
+++ b/chrome/common/apps/platform_apps/api/PRESUBMIT.py
@@ -0,0 +1,28 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Chromium presubmit script for src/chrome/common/apps/platform_apps.
+
+See https://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details on the presubmit API built into depot_tools.
+"""
+
+import sys
+
+
+def _CheckExterns(input_api, output_api):
+  original_sys_path = sys.path
+  join = input_api.os_path.join
+  src_root = input_api.change.RepositoryRoot()
+  try:
+    sys.path.append(join(src_root, 'extensions', 'common', 'api'))
+    from externs_checker import ExternsChecker
+  finally:
+    sys.path = original_sys_path
+
+  return ExternsChecker(input_api, output_api).RunChecks()
+
+
+def CheckChangeOnUpload(input_api, output_api):
+  return _CheckExterns(input_api, output_api)
diff --git a/chrome/common/apps/platform_apps/api/generated_externs_list.txt b/chrome/common/apps/platform_apps/api/generated_externs_list.txt
new file mode 100644
index 0000000..9eca6fb
--- /dev/null
+++ b/chrome/common/apps/platform_apps/api/generated_externs_list.txt
@@ -0,0 +1,3 @@
+# All APIs that have their externs generated.
+# TODO(rdevlin.cronin): Add more!
+arc_apps_private.idl
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 1c9a240..6699a54 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -571,6 +571,11 @@
                                         base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
+#if defined(OS_WIN)
+const base::Feature kSafetyCheckChromeCleanerChild{
+    "SafetyCheckChromeCleanerChild", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
 #if BUILDFLAG(ENABLE_PLUGINS)
 // Show Flash deprecation warning to users who have manually enabled Flash.
 // https://crbug.com/918428
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 9e8cde06..30bdb5a 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -358,6 +358,11 @@
 extern const base::Feature kSafetyCheckAndroid;
 #endif
 
+#if defined(OS_WIN)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kSafetyCheckChromeCleanerChild;
+#endif
+
 #if BUILDFLAG(ENABLE_PLUGINS)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kFlashDeprecationWarning;
diff --git a/chrome/common/performance_manager/OWNERS b/chrome/common/performance_manager/OWNERS
index 0a5168e1..7e4c8d7 100644
--- a/chrome/common/performance_manager/OWNERS
+++ b/chrome/common/performance_manager/OWNERS
@@ -1 +1,5 @@
-file://chrome/browser/performance_manager/OWNERS
+file://components/performance_manager/OWNERS
+
+# For IPC security review
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chrome/common/profiler/thread_profiler.cc b/chrome/common/profiler/thread_profiler.cc
index 025305d2..d9874f8 100644
--- a/chrome/common/profiler/thread_profiler.cc
+++ b/chrome/common/profiler/thread_profiler.cc
@@ -27,7 +27,11 @@
 #include "content/public/common/service_names.mojom.h"
 #include "services/service_manager/embedder/switches.h"
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) && BUILDFLAG(ENABLE_ARM_CFI_TABLE)
+#include "base/android/apk_assets.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/profiler/arm_cfi_table.h"
+#include "base/profiler/chrome_unwinder_android.h"
 #include "chrome/android/modules/stack_unwinder/public/module.h"
 
 extern "C" {
@@ -76,32 +80,53 @@
 const base::RepeatingCallback<std::vector<std::unique_ptr<base::Unwinder>>()>&
 GetCoreUnwindersFactory() {
   const auto create_unwinders_factory = []() {
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) && BUILDFLAG(ENABLE_ARM_CFI_TABLE)
+    static constexpr char kCfiFileName[] = "assets/unwind_cfi_32";
+
     // The module is loadable if the profiler is enabled for the current
     // process.
     CHECK(StackSamplingConfiguration::Get()
               ->IsProfilerEnabledForCurrentProcess());
 
-    struct UnwinderCreationState {
-      std::unique_ptr<stack_unwinder::Module> module;
-      std::unique_ptr<stack_unwinder::MemoryRegionsMap> memory_regions_map;
-    };
-    const auto create_unwinders = [](UnwinderCreationState* creation_state) {
-      std::vector<std::unique_ptr<base::Unwinder>> unwinders;
-      unwinders.push_back(creation_state->module->CreateNativeUnwinder(
-          creation_state->memory_regions_map.get(),
-          reinterpret_cast<uintptr_t>(&__executable_start)));
-      return unwinders;
+    class UnwindersFactory {
+     public:
+      UnwindersFactory()
+          : module_(stack_unwinder::Module::Load()),
+            memory_regions_map_(module_->CreateMemoryRegionsMap()) {
+        base::MemoryMappedFile::Region cfi_region;
+        int fd = base::android::OpenApkAsset(kCfiFileName, &cfi_region);
+        DCHECK(fd >= 0);
+        bool mapped_file_ok =
+            chrome_cfi_file_.Initialize(base::File(fd), cfi_region);
+        DCHECK(mapped_file_ok);
+        chrome_cfi_table_ = base::ArmCFITable::Parse(
+            {chrome_cfi_file_.data(), chrome_cfi_file_.length()});
+        DCHECK(chrome_cfi_table_);
+      }
+      UnwindersFactory(const UnwindersFactory&) = delete;
+      UnwindersFactory& operator=(const UnwindersFactory&) = delete;
+
+      std::vector<std::unique_ptr<base::Unwinder>> Run() {
+        std::vector<std::unique_ptr<base::Unwinder>> unwinders;
+        unwinders.push_back(module_->CreateNativeUnwinder(
+            memory_regions_map_.get(),
+            reinterpret_cast<uintptr_t>(&__executable_start)));
+        unwinders.push_back(std::make_unique<base::ChromeUnwinderAndroid>(
+            chrome_cfi_table_.get(),
+            reinterpret_cast<uintptr_t>(&__executable_start)));
+        return unwinders;
+      }
+
+     private:
+      const std::unique_ptr<stack_unwinder::Module> module_;
+      const std::unique_ptr<stack_unwinder::MemoryRegionsMap>
+          memory_regions_map_;
+      base::MemoryMappedFile chrome_cfi_file_;
+      std::unique_ptr<base::ArmCFITable> chrome_cfi_table_;
     };
 
-    std::unique_ptr<stack_unwinder::Module> module =
-        stack_unwinder::Module::Load();
-    std::unique_ptr<stack_unwinder::MemoryRegionsMap> memory_regions_map =
-        module->CreateMemoryRegionsMap();
-    return base::BindRepeating(
-        create_unwinders,
-        base::Owned(new UnwinderCreationState{std::move(module),
-                                              std::move(memory_regions_map)}));
+    return base::BindRepeating(&UnwindersFactory::Run,
+                               std::make_unique<UnwindersFactory>());
 #else
     return base::BindRepeating(
         []() -> std::vector<std::unique_ptr<base::Unwinder>> { return {}; });
diff --git a/chrome/renderer/performance_manager/OWNERS b/chrome/renderer/performance_manager/OWNERS
index 0a5168e1..6ef4e6d 100644
--- a/chrome/renderer/performance_manager/OWNERS
+++ b/chrome/renderer/performance_manager/OWNERS
@@ -1 +1 @@
-file://chrome/browser/performance_manager/OWNERS
+file://components/performance_manager/OWNERS
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorTestUtils.java
index 637263c3..4a432db 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorTestUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorTestUtils.java
@@ -4,9 +4,6 @@
 
 package org.chromium.chrome.browser.omnibox.suggestions;
 
-import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteMediator.DropdownItemViewInfo;
-import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
-
 /**
  * Utility methods providing access to package-private methods in {@link AutocompleteCoordinator}
  * for tests.
@@ -37,28 +34,4 @@
             AutocompleteCoordinator coordinator) {
         return ((AutocompleteCoordinatorImpl) coordinator).getSuggestionsDropdown();
     }
-
-    /**
-     * @return The {@link OmniboxSuggestion} at the specified index.
-     */
-    public static OmniboxSuggestion getOmniboxSuggestionAt(
-            AutocompleteCoordinator coordinator, int index) {
-        return coordinator.getSuggestionAt(index);
-    }
-
-    /**
-     * @return The index of the first suggestion which is |type|.
-     */
-    public static int getIndexForFirstSuggestionOfType(
-            AutocompleteCoordinator coordinator, @OmniboxSuggestionUiType int type) {
-        ModelList currentModels =
-                ((AutocompleteCoordinatorImpl) coordinator).getSuggestionModelList();
-        for (int i = 0; i < currentModels.size(); i++) {
-            DropdownItemViewInfo info = (DropdownItemViewInfo) currentModels.get(i);
-            if (info.type == type) {
-                return i;
-            }
-        }
-        return -1;
-    }
 }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/tests/NewTabPageControllerTest.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/tests/NewTabPageControllerTest.java
index b13bfdf..eedc516 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/tests/NewTabPageControllerTest.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/tests/NewTabPageControllerTest.java
@@ -19,6 +19,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.BaseJUnit4ClassRunner;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.test.pagecontroller.controllers.ntp.ChromeMenu;
 import org.chromium.chrome.test.pagecontroller.controllers.ntp.NewTabPageController;
 import org.chromium.chrome.test.pagecontroller.controllers.urlpage.UrlPage;
@@ -51,6 +52,7 @@
     }
 
     @Test
+    @DisabledTest(message = "https://crbug.com/1091640")
     public void testHideArticles() {
         boolean isHidden = mController.areArticlesHidden();
         mController.toggleHideArticles();
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestUtil.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestUtil.java
index 51900c48..03222ee 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestUtil.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestUtil.java
@@ -53,8 +53,7 @@
      */
     @WorkerThread
     public static void setUpAuthForTesting() {
-        sAccountManager = new FakeAccountManagerDelegate(
-                FakeAccountManagerDelegate.DISABLE_PROFILE_DATA_SOURCE);
+        sAccountManager = new FakeAccountManagerDelegate();
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             AccountManagerFacadeProvider.setInstanceForTests(
                     new AccountManagerFacadeImpl(sAccountManager));
diff --git a/chrome/test/base/ui_test_utils.cc b/chrome/test/base/ui_test_utils.cc
index 6bb4991..287c71c4 100644
--- a/chrome/test/base/ui_test_utils.cc
+++ b/chrome/test/base/ui_test_utils.cc
@@ -396,6 +396,7 @@
   find_in_page::FindTabHelper* find_tab_helper =
       find_in_page::FindTabHelper::FromWebContents(tab);
   find_tab_helper->StartFinding(search_string, forward, match_case,
+                                true, /* find_next_if_selection_matches */
                                 true /* run_synchronously_for_testing */);
   FindResultWaiter observer(tab);
   observer.Wait();
diff --git a/chrome/test/data/data_favicon.html b/chrome/test/data/data_favicon.html
new file mode 100644
index 0000000..19e22b6
--- /dev/null
+++ b/chrome/test/data/data_favicon.html
@@ -0,0 +1,5 @@
+<html>
+  <head></head>
+  <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
+  <body></body>
+</html>
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index e33ab66f..ca7809e5 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -4823,6 +4823,18 @@
     ]
   },
 
+  "PluginVmDataCollectionAllowed": {
+    "os": ["chromeos"],
+    "policy_pref_mapping_test": [
+      {
+        "policies": {
+
+          "PluginVmDataCollectionAllowed": false
+        },
+        "prefs": { "plugin_vm.data_collection_allowed": {} }
+      }
+    ]
+  },
 
   "VoiceInteractionHotwordEnabled": {
     "os": ["chromeos"],
diff --git a/chrome/test/data/signin/link_with_replacements.html b/chrome/test/data/signin/link_with_replacements.html
new file mode 100644
index 0000000..27e651f
--- /dev/null
+++ b/chrome/test/data/signin/link_with_replacements.html
@@ -0,0 +1,2 @@
+<p>This page has a link that should be replaced</a>
+<a href="REPLACE_WITH_URL">Go to URL</a>
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 9784082..d235286 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -363,12 +363,18 @@
                   ]
   deps = [
     ":chai_assert",
+    ":mock_timer.m",
     ":test_browser_proxy.m",
     ":test_plural_string_proxy",
     ":test_util.m",
   ]
 }
 
+js_library("mock_timer.m") {
+  sources = [ "$root_gen_dir/chrome/test/data/webui/mock_timer.m.js" ]
+  extra_deps = [ ":modulize_local" ]
+}
+
 js_library("test_util.m") {
   sources = [ "$root_gen_dir/chrome/test/data/webui/test_util.m.js" ]
   deps = [
diff --git a/chrome/test/data/webui/chromeos/crostini_installer_app_test.js b/chrome/test/data/webui/chromeos/crostini_installer_app_test.js
index 428acf6..8b11ff0d 100644
--- a/chrome/test/data/webui/chromeos/crostini_installer_app_test.js
+++ b/chrome/test/data/webui/chromeos/crostini_installer_app_test.js
@@ -14,7 +14,7 @@
 class FakePageHandler extends TestBrowserProxy {
   constructor() {
     super([
-      'install', 'cancel', 'cancelBeforeStart', 'close',
+      'install', 'cancel', 'cancelBeforeStart', 'onPageClosed',
       'requestAmountOfFreeDiskSpace'
     ]);
   }
@@ -35,8 +35,8 @@
   }
 
   /** @override */
-  close() {
-    this.methodCalled('close');
+  onPageClosed() {
+    this.methodCalled('onPageClosed');
   }
 
   /** @override */
@@ -101,6 +101,21 @@
     await clickButton(getCancelButton());
   };
 
+  const clickCustomSize = async () => {
+    await clickButton(app.$$('#custom-size'));
+  };
+
+  /**
+   * Checks whether a given element is hidden.
+   * @param {!Element} element
+   * @returns {boolean}
+   */
+  function isHidden(element) {
+    return (
+        !element || element.getBoundingClientRect().width <= 0 ||
+        element.hidden);
+  }
+
   const diskTicks = [
     {value: 1000, ariaValue: '1', label: '1'},
     {value: 2000, ariaValue: '2', label: '2'}
@@ -143,10 +158,10 @@
         app.$$('#installing-message > paper-progress').getAttribute('value'),
         '50');
 
-    expectEquals(fakeBrowserProxy.handler.getCallCount('close'), 0);
+    expectEquals(fakeBrowserProxy.handler.getCallCount('onPageClosed'), 0);
     fakeBrowserProxy.page.onInstallFinished(InstallerError.kNone);
     await flushTasks();
-    expectEquals(fakeBrowserProxy.handler.getCallCount('close'), 1);
+    expectEquals(fakeBrowserProxy.handler.getCallCount('onPageClosed'), 1);
   });
 
   // We only proceed to the config page if disk info is available. Let's make
@@ -215,6 +230,7 @@
 
       expectFalse(app.$$('#configure-message').hidden);
       expectTrue(app.$$('#low-free-space-warning').hidden);
+      expectTrue(isHidden(app.$$('#diskSlider')));
 
       await clickInstall();
       await fakeBrowserProxy.handler.whenCalled('install').then(
@@ -232,9 +248,12 @@
 
     await clickNext();
     await flushTasks();
+    await clickCustomSize();
+    await flushTasks();
 
     expectFalse(app.$$('#configure-message').hidden);
     expectTrue(app.$$('#low-free-space-warning').hidden);
+    expectFalse(isHidden(app.$$('#diskSlider')));
 
     app.$$('#diskSlider').value = 1;
 
@@ -303,7 +322,7 @@
         'error message should be set');
 
     await clickCancel();
-    expectEquals(fakeBrowserProxy.handler.getCallCount('close'), 1);
+    expectEquals(fakeBrowserProxy.handler.getCallCount('onPageClosed'), 1);
     expectEquals(fakeBrowserProxy.handler.getCallCount('cancelBeforeStart'), 0);
     expectEquals(fakeBrowserProxy.handler.getCallCount('cancel'), 0);
   });
@@ -323,27 +342,51 @@
     expectEquals(fakeBrowserProxy.handler.getCallCount('install'), 2);
   });
 
-  test('cancelBeforeStart', async () => {
-    await clickCancel();
+  [clickCancel,
+   () => fakeBrowserProxy.page.requestClose(),
+  ].forEach((canceller, i) => test(`cancelBeforeStart-{i}`, async () => {
+              await canceller();
+              await flushTasks();
+              expectEquals(
+                  fakeBrowserProxy.handler.getCallCount('cancelBeforeStart'),
+                  1);
+              expectEquals(
+                  fakeBrowserProxy.handler.getCallCount('onPageClosed'), 1);
+              expectEquals(fakeBrowserProxy.handler.getCallCount('cancel'), 0);
+            }));
+
+  // This is a special case that requestClose is different from clicking cancel
+  // --- instead of going back to the previous page, requestClose should close
+  // the page immediately.
+  test('requestCloseAtConfigPage', async () => {
+    await clickNext();  // Progress to config page.
+    await fakeBrowserProxy.page.requestClose();
+    await flushTasks();
     expectEquals(fakeBrowserProxy.handler.getCallCount('cancelBeforeStart'), 1);
-    expectEquals(fakeBrowserProxy.handler.getCallCount('close'), 1);
+    expectEquals(fakeBrowserProxy.handler.getCallCount('onPageClosed'), 1);
     expectEquals(fakeBrowserProxy.handler.getCallCount('cancel'), 0);
   });
 
-  test('cancelAfterStart', async () => {
-    fakeBrowserProxy.page.onAmountOfFreeDiskSpace(diskTicks, 0, false);
-    await clickNext();
-    await clickInstall();
-    await clickCancel();
-    expectEquals(fakeBrowserProxy.handler.getCallCount('cancel'), 1);
-    expectEquals(
-        fakeBrowserProxy.handler.getCallCount('close'), 0,
-        'should not close until onCanceled is called');
-    expectTrue(getInstallButton().hidden);
-    expectTrue(getCancelButton().disabled);
 
-    fakeBrowserProxy.page.onCanceled();
-    await flushTasks();
-    expectEquals(fakeBrowserProxy.handler.getCallCount('close'), 1);
-  });
+  [clickCancel,
+   () => fakeBrowserProxy.page.requestClose(),
+  ].forEach((canceller, i) => test(`cancelAfterStart-{i}`, async () => {
+              fakeBrowserProxy.page.onAmountOfFreeDiskSpace(
+                  diskTicks, 0, false);
+              await clickNext();
+              await clickInstall();
+              await canceller();
+              await flushTasks();
+              expectEquals(fakeBrowserProxy.handler.getCallCount('cancel'), 1);
+              expectEquals(
+                  fakeBrowserProxy.handler.getCallCount('onPageClosed'), 0,
+                  'should not close until onCanceled is called');
+              expectTrue(getInstallButton().hidden);
+              expectTrue(getCancelButton().disabled);
+
+              fakeBrowserProxy.page.onCanceled();
+              await flushTasks();
+              expectEquals(
+                  fakeBrowserProxy.handler.getCallCount('onPageClosed'), 1);
+            }));
 });
diff --git a/chrome/test/data/webui/chromeos/crostini_upgrader_app_test.js b/chrome/test/data/webui/chromeos/crostini_upgrader_app_test.js
index bdd1e840..352687b 100644
--- a/chrome/test/data/webui/chromeos/crostini_upgrader_app_test.js
+++ b/chrome/test/data/webui/chromeos/crostini_upgrader_app_test.js
@@ -12,7 +12,7 @@
   constructor() {
     super([
       'backup', 'startPrechecks', 'upgrade', 'restore', 'cancel',
-      'cancelBeforeStart', 'close', 'launch'
+      'cancelBeforeStart', 'onPageClosed', 'launch'
     ]);
   }
 
@@ -47,8 +47,8 @@
   }
 
   /** @override */
-  close() {
-    this.methodCalled('close');
+  onPageClosed() {
+    this.methodCalled('onPageClosed');
   }
 
   /** @override */
@@ -169,12 +169,12 @@
     fakeBrowserProxy.page.onUpgradeSucceeded();
     await flushTasks();
 
-    expectEquals(fakeBrowserProxy.handler.getCallCount('close'), 0);
+    expectEquals(fakeBrowserProxy.handler.getCallCount('onPageClosed'), 0);
     expectTrue(getRestoreProgressBar().hidden);
 
     await clickAction();
     expectEquals(fakeBrowserProxy.handler.getCallCount('launch'), 1);
-    expectEquals(fakeBrowserProxy.handler.getCallCount('close'), 1);
+    expectEquals(fakeBrowserProxy.handler.getCallCount('onPageClosed'), 1);
   });
 
   test('upgradeFlowFailureOffersRestore', async () => {
@@ -223,6 +223,6 @@
 
     await clickAction();
     expectEquals(fakeBrowserProxy.handler.getCallCount('launch'), 1);
-    expectEquals(fakeBrowserProxy.handler.getCallCount('close'), 1);
+    expectEquals(fakeBrowserProxy.handler.getCallCount('onPageClosed'), 1);
   });
 });
diff --git a/chrome/test/data/webui/cr_elements/BUILD.gn b/chrome/test/data/webui/cr_elements/BUILD.gn
index 9aa25d8..f8cee9f8 100644
--- a/chrome/test/data/webui/cr_elements/BUILD.gn
+++ b/chrome/test/data/webui/cr_elements/BUILD.gn
@@ -81,10 +81,10 @@
     ":cr_slider_test.m",
     ":cr_splitter_test",
     ":cr_tabs_test.m",
+    ":cr_toast_manager_test.m",
+    ":cr_toast_test.m",
+    ":cr_toggle_test.m",
 
-    #":cr_toast_manager_test",
-    #":cr_toast_test",
-    #":cr_toggle_test",
     #":cr_toolbar_search_field_tests",
     #":cr_view_manager_test",
     #":iron_list_focus_test",
@@ -422,3 +422,40 @@
   externs_list = [ "$externs_path/mocha-2.5.js" ]
   extra_deps = [ ":modulize" ]
 }
+
+js_library("cr_toast_manager_test.m") {
+  sources = [ "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_toast_manager_test.m.js" ]
+  deps = [
+    "..:chai_assert",
+    "..:test_util.m",
+    "//ui/webui/resources/cr_elements/cr_toast:cr_toast.m",
+    "//ui/webui/resources/cr_elements/cr_toast:cr_toast_manager.m",
+  ]
+  externs_list = [ "$externs_path/mocha-2.5.js" ]
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("cr_toast_test.m") {
+  sources =
+      [ "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_toast_test.m.js" ]
+  deps = [
+    "..:chai_assert",
+    "..:mock_timer.m",
+    "//ui/webui/resources/cr_elements/cr_toast:cr_toast.m",
+  ]
+  externs_list = [ "$externs_path/mocha-2.5.js" ]
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("cr_toggle_test.m") {
+  sources =
+      [ "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_toggle_test.m.js" ]
+  deps = [
+    "..:chai_assert",
+    "..:test_util.m",
+    "//third_party/polymer/v3_0/components-chromium/iron-test-helpers:mock-interactions",
+    "//ui/webui/resources/cr_elements/cr_toggle:cr_toggle.m",
+  ]
+  externs_list = [ "$externs_path/mocha-2.5.js" ]
+  extra_deps = [ ":modulize" ]
+}
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.js b/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.js
index 44321f1..3e22a7f 100644
--- a/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.js
@@ -41,6 +41,7 @@
     Polymer.dom.flush();
     assertTrue(icon.hidden);
 
+    // Check indicator behavior for a preference controlled by the device owner.
     indicator.set(
         'pref.controlledBy', chrome.settingsPrivate.ControlledBy.OWNER);
     indicator.set('pref.controlledByName', 'owner_name');
@@ -51,6 +52,8 @@
     assertEquals('cr:person', icon.iconClass);
     assertEquals('owner: owner_name', icon.tooltipText);
 
+    // Check indicator behavior for a preference with a recommended value that
+    // is different from the current value of the preference.
     indicator.set('pref.value', 'foo');
     indicator.set('pref.recommendedValue', 'bar');
     indicator.set(
@@ -60,10 +63,14 @@
     assertEquals('cr20:domain', icon.iconClass);
     assertEquals('differs', icon.tooltipText);
 
+    // Check indicator behavior for a preference with a recommended value that
+    // is the same as the current value of the preference.
     indicator.set('pref.value', 'bar');
     Polymer.dom.flush();
     assertEquals('matches', icon.tooltipText);
 
+    // Check indicator behavior for a preference that is enforced for a
+    // supervised user.
     indicator.set(
         'pref.enforcement',
         chrome.settingsPrivate.Enforcement.PARENT_SUPERVISED);
@@ -71,5 +78,62 @@
     assertFalse(icon.hidden);
     assertEquals('cr20:kite', icon.iconClass);
     assertEquals(CrPolicyStrings.controlledSettingParent, icon.tooltipText);
+
+    // Check indicator behavior for a preference that is enforced by device
+    // policy.
+    indicator.set(
+        'pref.enforcement', chrome.settingsPrivate.Enforcement.ENFORCED);
+    indicator.set(
+        'pref.controlledBy', chrome.settingsPrivate.ControlledBy.DEVICE_POLICY);
+    Polymer.dom.flush();
+    assertFalse(icon.hidden);
+    assertEquals('cr20:domain', icon.iconClass);
+    assertEquals(CrPolicyStrings.controlledSettingPolicy, icon.tooltipText);
+
+    // Check indicator behavior for an preference that is enforced whilst also
+    // having a recommended value.
+    const indicatorPrefValue = 1;
+    const differentPrefValue = 2;
+    indicator.set(
+        'pref.enforcement', chrome.settingsPrivate.Enforcement.ENFORCED);
+
+    indicator.set('associatedValue', indicatorPrefValue);
+    indicator.set(
+        'pref.userSelectableValues', [indicatorPrefValue, differentPrefValue]);
+    Polymer.dom.flush();
+    assertTrue(icon.hidden);
+
+    indicator.set('pref.recommendedValue', differentPrefValue);
+    indicator.set('pref.value', differentPrefValue);
+    Polymer.dom.flush();
+    assertTrue(icon.hidden);
+
+    indicator.set('pref.recommendedValue', indicatorPrefValue);
+    assertEquals('cr20:domain', icon.iconClass);
+    assertEquals('differs', icon.tooltipText);
+
+    indicator.set('pref.value', indicatorPrefValue);
+    Polymer.dom.flush();
+    assertEquals('matches', icon.tooltipText);
+
+    // Check indicator behavior for an preference that is recommended whilst the
+    // indicator has an associated value.
+    indicator.set(
+        'pref.enforcement', chrome.settingsPrivate.Enforcement.RECOMMENDED);
+    indicator.set('pref.userSelectableValues', []);
+    indicator.set('pref.value', differentPrefValue);
+
+    indicator.set('pref.recommendedValue', differentPrefValue);
+    Polymer.dom.flush();
+    assertTrue(icon.hidden);
+
+    indicator.set('pref.recommendedValue', indicatorPrefValue);
+    assertEquals('cr20:domain', icon.iconClass);
+    assertEquals('differs', icon.tooltipText);
+
+    indicator.set('pref.value', indicatorPrefValue);
+    Polymer.dom.flush();
+    assertEquals('matches', icon.tooltipText);
+
   });
 });
diff --git a/chrome/test/data/webui/cr_elements/cr_toast_manager_test.js b/chrome/test/data/webui/cr_elements/cr_toast_manager_test.js
index 8628002..1448bca4 100644
--- a/chrome/test/data/webui/cr_elements/cr_toast_manager_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_toast_manager_test.js
@@ -5,14 +5,17 @@
 // clang-format off
 // #import {getToastManager} from 'chrome://resources/cr_elements/cr_toast/cr_toast_manager.m.js';
 // #import {eventToPromise} from '../test_util.m.js';
+// #import {assertEquals, assertFalse, assertTrue} from '../chai_assert.js';
 // clang-format on
 
 suite('cr-toast-manager', () => {
+  /** @type {!CrToastManagerElement} */
   let toastManager;
 
   suiteSetup(() => {
-    PolymerTest.clearBody();
-    toastManager = document.createElement('cr-toast-manager');
+    document.body.innerHTML = '';
+    toastManager = /** @type {!CrToastManagerElement} */ (
+        document.createElement('cr-toast-manager'));
     document.body.appendChild(toastManager);
   });
 
@@ -45,6 +48,7 @@
 
   test('duration passed through to toast', () => {
     toastManager.duration = 3;
-    assertEquals(3, toastManager.$.toast.duration);
+    assertEquals(
+        3, /** @type {!CrToastElement} */ (toastManager.$$('#toast').duration));
   });
 });
diff --git a/chrome/test/data/webui/cr_elements/cr_toast_test.js b/chrome/test/data/webui/cr_elements/cr_toast_test.js
index da67dcd6..a23cc43 100644
--- a/chrome/test/data/webui/cr_elements/cr_toast_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_toast_test.js
@@ -5,15 +5,19 @@
 // clang-format off
 // #import 'chrome://resources/cr_elements/cr_toast/cr_toast.m.js';
 // #import {MockTimer} from '../mock_timer.m.js';
+// #import {assertEquals, assertFalse, assertTrue} from '../chai_assert.js';
 // clang-format on
 
 suite('cr-toast', function() {
+  /** @type {!CrToastElement} */
   let toast;
+
+  /** @type {!MockTimer} */
   let mockTimer;
 
   setup(function() {
-    PolymerTest.clearBody();
-    toast = document.createElement('cr-toast');
+    document.body.innerHTML = '';
+    toast = /** @type {!CrToastElement} */ (document.createElement('cr-toast'));
     document.body.appendChild(toast);
     mockTimer = new MockTimer();
     mockTimer.install();
diff --git a/chrome/test/data/webui/cr_elements/cr_toggle_test.js b/chrome/test/data/webui/cr_elements/cr_toggle_test.js
index 1dd83e4..7c758b2 100644
--- a/chrome/test/data/webui/cr_elements/cr_toggle_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_toggle_test.js
@@ -6,18 +6,18 @@
 // #import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.m.js';
 // #import {keyEventOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
 // #import {eventToPromise} from '../test_util.m.js';
+// #import {assertEquals, assertFalse, assertTrue} from '../chai_assert.js';
 // clang-format on
 
 suite('cr-toggle', function() {
+  /** @type {!CrToggleElement} */
   let toggle;
 
   setup(function() {
-    PolymerTest.clearBody();
-    document.body.innerHTML = `
-      <cr-toggle id="toggle"></cr-toggle>
-    `;
-
-    toggle = document.getElementById('toggle');
+    document.body.innerHTML = '';
+    toggle =
+        /** @type {!CrToggleElement} */ (document.createElement('cr-toggle'));
+    document.body.appendChild(toggle);
     assertNotChecked();
   });
 
@@ -26,7 +26,8 @@
     assertTrue(toggle.hasAttribute('checked'));
     assertEquals('true', toggle.getAttribute('aria-pressed'));
     // Asserting that the toggle button has actually moved.
-    assertTrue(getComputedStyle(toggle.$.knob).transform.includes('matrix'));
+    assertTrue(
+        getComputedStyle(toggle.$$('#knob')).transform.includes('matrix'));
   }
 
   function assertNotChecked() {
@@ -34,7 +35,7 @@
     assertEquals(null, toggle.getAttribute('checked'));
     assertEquals('false', toggle.getAttribute('aria-pressed'));
     // Asserting that the toggle button has not moved.
-    assertEquals('none', getComputedStyle(toggle.$.knob).transform);
+    assertEquals('none', getComputedStyle(toggle.$$('#knob')).transform);
   }
 
   function assertDisabled() {
diff --git a/chrome/test/data/webui/mock_timer.js b/chrome/test/data/webui/mock_timer.js
index ac29b107..dc97f8e 100644
--- a/chrome/test/data/webui/mock_timer.js
+++ b/chrome/test/data/webui/mock_timer.js
@@ -23,10 +23,10 @@
 
     /**
      * Details for active timers.
-     * @type {Array<{callback: Function,
+     * @type {!Array<{callback: Function,
      *                delay: number,
      *                key: number,
-     *                repeats: boolean}>}
+     *                repeats: boolean}|undefined>}
      * @private
      */
     this.timers_ = [];
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn
index f4b2d0a..b092e577 100644
--- a/chrome/test/data/webui/settings/BUILD.gn
+++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -132,6 +132,7 @@
     #":reset_page_test",
     #":reset_profile_banner_test",
     #":route_tests",
+    ":safety_check_chrome_cleaner_test",
     ":safety_check_page_test",
 
     #":search_engines_page_test",
@@ -244,6 +245,15 @@
   ]
 }
 
+js_library("safety_check_chrome_cleaner_test") {
+  deps = [
+    ":test_metrics_browser_proxy",
+    "..:chai_assert",
+    "//chrome/browser/resources/settings:settings",
+  ]
+  externs_list = [ "$externs_path/mocha-2.5.js" ]
+}
+
 js_library("safety_check_page_test") {
   deps = [
     ":test_hats_browser_proxy",
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_search_box_test.js b/chrome/test/data/webui/settings/chromeos/os_settings_search_box_test.js
index 3671138..56da580d 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_search_box_test.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_search_box_test.js
@@ -5,6 +5,18 @@
 /** @fileoverview Runs tests for the OS settings search box. */
 
 suite('OSSettingsSearchBox', () => {
+  // TODO(hsuregan): Keep count and add getters for metrics.
+  class MockMetricsPrivate {
+    // Used by <os-search-result-row>
+    recordEnumerationValue(metricName, value, enumSize) {}
+
+    // Used by <os-search-result-row>
+    recordSparseValue(metricName, value) {}
+
+    // Required to use recordSparsValue()
+    recordSparseHashable(metricName, value) {}
+  }
+
   /** @const {number} */
   const DEFAULT_RELEVANCE_SCORE = 0.5;
 
@@ -63,12 +75,19 @@
       },
       urlPathWithParameters: urlPathWithParameters,
       icon: icon ? icon : chromeos.settings.mojom.SearchResultIcon.MIN_VALUE,
+      id: {
+        section: chromeos.settings.mojom.Section.MIN_VALUE,
+        subpage: chromeos.settings.mojom.Subpage.MIN_VALUE,
+        setting: chromeos.settings.mojom.Setting.MIN_VALUE,
+      },
+      type: chromeos.settings.mojom.SearchResultType.MIN_VALUE,
       relevanceScore: DEFAULT_RELEVANCE_SCORE,
       settingsPageHierarchy: DEFAULT_PAGE_HIERARCHY,
     });
   }
 
   setup(function() {
+    chrome.metricsPrivate = new MockMetricsPrivate();
     toolbar = document.querySelector('os-settings-ui').$$('os-toolbar');
     assertTrue(!!toolbar);
     searchBox = toolbar.$$('os-settings-search-box');
diff --git a/chrome/test/data/webui/settings/collapse_radio_button_tests.js b/chrome/test/data/webui/settings/collapse_radio_button_tests.js
index 1d37e52..53d9fe1 100644
--- a/chrome/test/data/webui/settings/collapse_radio_button_tests.js
+++ b/chrome/test/data/webui/settings/collapse_radio_button_tests.js
@@ -100,4 +100,61 @@
     flush();
     assertTrue(isChildVisible(collapseRadioButton, '#policyIndicator'));
   });
+
+  test('respectPreferenceState', function() {
+    const togglePrefValue = 'pref_value';
+    collapseRadioButton.name = togglePrefValue;
+    collapseRadioButton.pref = {
+      type: chrome.settingsPrivate.PrefType.NUMBER,
+      enforcement: chrome.settingsPrivate.Enforcement.ENFORCED,
+      controlledBy: chrome.settingsPrivate.ControlledBy.DEVICE_POLICY,
+    };
+    flush();
+    assertTrue(isChildVisible(collapseRadioButton, 'cr-policy-pref-indicator'));
+    assertTrue(collapseRadioButton.disabled);
+
+    collapseRadioButton.set('pref.userSelectableValues', ['unrelated-value']);
+    flush();
+    assertTrue(isChildVisible(collapseRadioButton, 'cr-policy-pref-indicator'));
+    assertTrue(collapseRadioButton.disabled);
+
+    collapseRadioButton.set('pref.userSelectableValues', [togglePrefValue]);
+    flush();
+    assertFalse(
+        isChildVisible(collapseRadioButton, 'cr-policy-pref-indicator'));
+    assertFalse(collapseRadioButton.disabled);
+
+    collapseRadioButton.set(
+        'pref.enforcement', chrome.settingsPrivate.Enforcement.RECOMMENDED);
+    collapseRadioButton.set('pref.recommendedValue', 'unrelated-value');
+    flush();
+    assertFalse(
+        isChildVisible(collapseRadioButton, 'cr-policy-pref-indicator'));
+    assertFalse(collapseRadioButton.disabled);
+
+    collapseRadioButton.set('pref.recommendedValue', togglePrefValue);
+    assertTrue(isChildVisible(collapseRadioButton, 'cr-policy-pref-indicator'));
+    assertFalse(collapseRadioButton.disabled);
+  });
+
+  test('singlePolicyIndicator', function() {
+    assertFalse(isChildVisible(collapseRadioButton, '#policyIndicator'));
+    assertFalse(
+        isChildVisible(collapseRadioButton, 'cr-policy-pref-indicator'));
+
+    collapseRadioButton.policyIndicatorType =
+        CrPolicyIndicatorType.DEVICE_POLICY;
+    flush();
+    assertTrue(isChildVisible(collapseRadioButton, '#policyIndicator'));
+    assertFalse(
+        isChildVisible(collapseRadioButton, 'cr-policy-pref-indicator'));
+
+    collapseRadioButton.pref = {
+      enforcement: chrome.settingsPrivate.Enforcement.ENFORCED,
+      controlledBy: chrome.settingsPrivate.ControlledBy.DEVICE_POLICY,
+    };
+    flush();
+    assertFalse(isChildVisible(collapseRadioButton, '#policyIndicator'));
+    assertTrue(isChildVisible(collapseRadioButton, 'cr-policy-pref-indicator'));
+  });
 });
diff --git a/chrome/test/data/webui/settings/cookies_page_test.js b/chrome/test/data/webui/settings/cookies_page_test.js
index 6c8b829..de8a8df0 100644
--- a/chrome/test/data/webui/settings/cookies_page_test.js
+++ b/chrome/test/data/webui/settings/cookies_page_test.js
@@ -28,27 +28,6 @@
   /** @type {!SettingsCookiesPageElement} */
   let page;
 
-  /** @type {!SettingsToggleButtonElement} */
-  let clearOnExit;
-
-  /** @type {!SettingsToggleButtonElement} */
-  let networkPrediction;
-
-  /** @type {!SettingsCollapseRadioButtonElement} */
-  let allowAll;
-
-  /** @type {!SettingsCollapseRadioButtonElement} */
-  let blockThirdPartyIncognito;
-
-  /** @type {!SettingsCollapseRadioButtonElement} */
-  let blockThirdParty;
-
-  /** @type {!SettingsCollapseRadioButtonElement} */
-  let blockAll;
-
-  /** @type {!Array<!SettingsCollapseRadioButtonElement>} */
-  let radioButtons;
-
   suiteSetup(function() {
     loadTimeData.overrideValues({
       improvedCookieControlsEnabled: true,
@@ -64,141 +43,20 @@
     page = /** @type {!SettingsCookiesPageElement} */ (
         document.createElement('settings-cookies-page'));
     page.prefs = {
-      profile: {
-        cookie_controls_mode: {value: 0},
-        block_third_party_cookies: {value: false},
+      generated: {
+        cookie_session_only: {value: false},
+        cookie_primary_setting:
+            {type: chrome.settingsPrivate.PrefType.NUMBER, value: 0},
       },
     };
     document.body.appendChild(page);
     flush();
-
-    radioButtons = /** @type {!Array<!SettingsCollapseRadioButtonElement>} */ ([
-      page.$$('#allowAll'),
-      page.$$('#blockThirdPartyIncognito'),
-      page.$$('#blockThirdParty'),
-      page.$$('#blockAll'),
-    ]);
-    [allowAll, blockThirdPartyIncognito, blockThirdParty, blockAll] =
-        radioButtons;
-
-    clearOnExit =
-        /** @type {!SettingsToggleButtonElement} */ (page.$$('#clearOnExit'));
-    networkPrediction = /** @type {!SettingsToggleButtonElement} */ (
-        page.$$('#networkPrediction'));
   });
 
   teardown(function() {
     page.remove();
   });
 
-  /**
-   * Updates the test proxy with the desired content setting for cookies.
-   * @param {ContentSetting} setting
-   */
-  async function updateTestCookieContentSetting(setting) {
-    const defaultPrefs = createSiteSettingsPrefs(
-        [createContentSettingTypeToValuePair(
-            ContentSettingsTypes.COOKIES, createDefaultContentSetting({
-              setting: setting,
-            }))],
-        []);
-    siteSettingsBrowserProxy.setPrefs(defaultPrefs);
-    await siteSettingsBrowserProxy.whenCalled('getDefaultValueForContentType');
-    siteSettingsBrowserProxy.reset();
-    flush();
-  }
-
-  test('ChangingCookieSettings', async function() {
-    // Each radio button updates two preferences and sets a content setting
-    // based on the state of the clear on exit toggle. This enumerates the
-    // expected behavior for each radio button for testing.
-    const testList = [
-      {
-        element: blockAll,
-        updates: {
-          contentSetting: ContentSetting.BLOCK,
-          cookieControlsMode: CookieControlsMode.BLOCK_THIRD_PARTY,
-          blockThirdParty: true,
-        },
-      },
-      {
-        element: blockThirdParty,
-        updates: {
-          contentSetting: ContentSetting.ALLOW,
-          cookieControlsMode: CookieControlsMode.BLOCK_THIRD_PARTY,
-          blockThirdParty: true,
-        },
-      },
-      {
-        element: blockThirdPartyIncognito,
-        updates: {
-          contentSetting: ContentSetting.ALLOW,
-          cookieControlsMode: CookieControlsMode.INCOGNITO_ONLY,
-          blockThirdParty: false,
-        },
-      },
-      {
-        element: allowAll,
-        updates: {
-          contentSetting: ContentSetting.ALLOW,
-          cookieControlsMode: CookieControlsMode.OFF,
-          blockThirdParty: false,
-        },
-      }
-    ];
-    await updateTestCookieContentSetting(ContentSetting.ALLOW);
-
-    for (const test of testList) {
-      test.element.click();
-      const update = await siteSettingsBrowserProxy.whenCalled(
-          'setDefaultValueForContentType');
-      flush();
-      assertEquals(update[0], ContentSettingsTypes.COOKIES);
-      assertEquals(update[1], test.updates.contentSetting);
-      assertEquals(
-          page.prefs.profile.cookie_controls_mode.value,
-          test.updates.cookieControlsMode);
-      assertEquals(
-          page.prefs.profile.block_third_party_cookies.value,
-          test.updates.blockThirdParty);
-
-      // Calls to setDefaultValueForContentType don't actually update the test
-      // proxy internals, so we need to manually update them.
-      await updateTestCookieContentSetting(test.updates.contentSetting);
-      siteSettingsBrowserProxy.reset();
-    }
-  });
-
-  test('RespectChangedCookieSetting_ContentSetting', async function() {
-    await updateTestCookieContentSetting(ContentSetting.BLOCK);
-    assertTrue(blockAll.checked);
-    siteSettingsBrowserProxy.reset();
-
-    await updateTestCookieContentSetting(ContentSetting.ALLOW);
-    assertTrue(allowAll.checked);
-    siteSettingsBrowserProxy.reset();
-
-    await updateTestCookieContentSetting(ContentSetting.SESSION_ONLY);
-    assertTrue(allowAll.checked);
-    siteSettingsBrowserProxy.reset();
-  });
-
-  test('RespectChangedCookieSetting_CookieControlPref', async function() {
-    page.set(
-        'prefs.profile.cookie_controls_mode.value',
-        CookieControlsMode.INCOGNITO_ONLY);
-    flush();
-    await siteSettingsBrowserProxy.whenCalled('getDefaultValueForContentType');
-    assertTrue(blockThirdPartyIncognito.checked);
-  });
-
-  test('RespectChangedCookieSetting_BlockThirdPartyPref', async function() {
-    page.set('prefs.profile.block_third_party_cookies.value', true);
-    flush();
-    await siteSettingsBrowserProxy.whenCalled('getDefaultValueForContentType');
-    assertTrue(blockThirdParty.checked);
-  });
-
   test('ElementVisibility', async function() {
     await flushTasks();
     assertTrue(isChildVisible(page, '#clearOnExit'));
@@ -206,11 +64,11 @@
     assertTrue(isChildVisible(page, '#networkPrediction'));
     // Ensure that with the improvedCookieControls flag enabled that the block
     // third party cookies radio is visible.
-    assertTrue(isVisible(blockThirdPartyIncognito));
+    assertTrue(isChildVisible(page, '#blockThirdPartyIncognito'));
   });
 
   test('NetworkPredictionClickRecorded', async function() {
-    networkPrediction.click();
+    page.$$('#networkPrediction').click();
     const result =
         await testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram');
     assertEquals(PrivacyElementInteractions.NETWORK_PREDICTION, result);
@@ -223,41 +81,38 @@
   });
 
   test('CookiesRadioClicksRecorded', async function() {
-    allowAll.click();
+    page.$$('#blockAll').click();
     let result =
         await testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram');
-    assertEquals(PrivacyElementInteractions.COOKIES_ALL, result);
-
+    assertEquals(PrivacyElementInteractions.COOKIES_BLOCK, result);
     testMetricsBrowserProxy.reset();
 
-    blockThirdPartyIncognito.click();
-    result =
-        await testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram');
-    assertEquals(PrivacyElementInteractions.COOKIES_INCOGNITO, result);
-
-    testMetricsBrowserProxy.reset();
-
-    blockThirdParty.click();
+    page.$$('#blockThirdParty').click();
     result =
         await testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram');
     assertEquals(PrivacyElementInteractions.COOKIES_THIRD, result);
-
     testMetricsBrowserProxy.reset();
 
-    blockAll.click();
+    page.$$('#blockThirdPartyIncognito').click();
     result =
         await testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram');
-    assertEquals(PrivacyElementInteractions.COOKIES_BLOCK, result);
+    assertEquals(PrivacyElementInteractions.COOKIES_INCOGNITO, result);
+    testMetricsBrowserProxy.reset();
+
+    page.$$('#allowAll').click();
+    result =
+        await testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram');
+    assertEquals(PrivacyElementInteractions.COOKIES_ALL, result);
+    testMetricsBrowserProxy.reset();
   });
 
-  test('CookiseSessionOnlyClickRecorded', async function() {
-    clearOnExit.click();
+  test('CookiesSessionOnlyClickRecorded', async function() {
+    page.$$('#clearOnExit').click();
     const result =
         await testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram');
     assertEquals(PrivacyElementInteractions.COOKIES_SESSION, result);
   });
 
-
   test('CookieSettingExceptions_Search', async function() {
     const exceptionPrefs = createSiteSettingsPrefs([], [
       createContentSettingTypeToValuePair(
@@ -297,80 +152,54 @@
     }
   });
 
-  test('CookieControls_ManagedState', async function() {
-    const managedControlState = {
-      allowAll:
-          {disabled: true, indicator: CrPolicyIndicatorType.DEVICE_POLICY},
-      blockThirdPartyIncognito:
-          {disabled: true, indicator: CrPolicyIndicatorType.DEVICE_POLICY},
-      blockThirdParty:
-          {disabled: true, indicator: CrPolicyIndicatorType.DEVICE_POLICY},
-      blockAll:
-          {disabled: true, indicator: CrPolicyIndicatorType.DEVICE_POLICY},
-      sessionOnly:
-          {disabled: true, indicator: CrPolicyIndicatorType.DEVICE_POLICY},
-    };
-    const managedPrefs = createSiteSettingsPrefs(
-        [createContentSettingTypeToValuePair(
-            ContentSettingsTypes.COOKIES, createDefaultContentSetting({
-              setting: ContentSetting.SESSION_ONLY,
-              source: SiteSettingSource.POLICY
-            }))],
-        []);
-    siteSettingsBrowserProxy.setCookieControlsManagedState(managedControlState);
-    siteSettingsBrowserProxy.setPrefs(managedPrefs);
-    await siteSettingsBrowserProxy.whenCalled('getDefaultValueForContentType');
-    await siteSettingsBrowserProxy.whenCalled('getCookieControlsManagedState');
-    flush();
-
-    // Check the four radio buttons are correctly indicating they are managed.
-    for (const button of radioButtons) {
-      assertTrue(button.disabled);
-      assertEquals(button.policyIndicatorType, 'devicePolicy');
-    }
-
-    // Check all exception lists are read only.
+  test('ExceptionLists_ReadOnly', async function() {
+    // Check all exception lists are read only when the session only preference
+    // reports as managed.
+    page.set('prefs.generated.cookie_session_only', {
+      value: true,
+      enforcement: chrome.settingsPrivate.Enforcement.ENFORCED,
+    });
     let exceptionLists = page.shadowRoot.querySelectorAll('site-list');
     assertEquals(exceptionLists.length, 3);
     for (const list of exceptionLists) {
       assertTrue(!!list.readOnlyList);
     }
 
-    // Revert to an unmanaged state and ensure all controls return to unmanged.
-    const unmanagedControlState = {
-      allowAll: {disabled: false, indicator: CrPolicyIndicatorType.NONE},
-      blockThirdPartyIncognito:
-          {disabled: false, indicator: CrPolicyIndicatorType.NONE},
-      blockThirdParty: {disabled: false, indicator: CrPolicyIndicatorType.NONE},
-      blockAll: {disabled: false, indicator: CrPolicyIndicatorType.NONE},
-      sessionOnly: {disabled: false, indicator: CrPolicyIndicatorType.NONE},
-    };
-    const unmanagedPrefs = createSiteSettingsPrefs(
-        [createContentSettingTypeToValuePair(
-            ContentSettingsTypes.COOKIES, createDefaultContentSetting({
-              setting: ContentSetting.ALLOW,
-            }))],
-        []);
-    siteSettingsBrowserProxy.reset();
-    siteSettingsBrowserProxy.setCookieControlsManagedState(
-        unmanagedControlState);
-    siteSettingsBrowserProxy.setPrefs(unmanagedPrefs);
-    await siteSettingsBrowserProxy.whenCalled('getDefaultValueForContentType');
-    await siteSettingsBrowserProxy.whenCalled('getCookieControlsManagedState');
-
-    // Check the four radio buttons no longer indicate they are managed.
-    for (const button of radioButtons) {
-      assertFalse(button.disabled);
-      assertEquals(button.policyIndicatorType, 'none');
-    }
-
-    // Check all exception lists are no longer read only.
+    // Return preference to unmanaged state and check all exception lists
+    // are no longer read only.
+    page.set('prefs.generated.cookie_session_only', {
+      value: true,
+    });
     exceptionLists = page.shadowRoot.querySelectorAll('site-list');
     assertEquals(exceptionLists.length, 3);
     for (const list of exceptionLists) {
       assertFalse(!!list.readOnlyList);
     }
   });
+
+  test('BlockAll_ManagementSource', async function() {
+    // Test that controlledBy for the blockAll_ preference is set to
+    // the same value as the generated.cookie_session_only preference.
+    const blockAll = page.$$('#blockAll');
+    page.set('prefs.generated.cookie_session_only', {
+      value: true,
+      enforcement: chrome.settingsPrivate.Enforcement.ENFORCED,
+      controlledBy: chrome.settingsPrivate.ControlledBy.EXTENSION,
+    });
+    flush();
+    assertEquals(
+        blockAll.pref.controlledBy,
+        chrome.settingsPrivate.ControlledBy.EXTENSION);
+
+    page.set('prefs.generated.cookie_session_only', {
+      value: true,
+      enforcement: chrome.settingsPrivate.Enforcement.ENFORCED,
+      controlledBy: chrome.settingsPrivate.ControlledBy.DEVICE_POLICY
+    });
+    assertEquals(
+        blockAll.pref.controlledBy,
+        chrome.settingsPrivate.ControlledBy.DEVICE_POLICY);
+  });
 });
 
 suite('CrSettingsCookiesPageTest_ImprovedCookieControlsDisabled', function() {
@@ -393,9 +222,10 @@
     page = /** @type {!SettingsCookiesPageElement} */ (
         document.createElement('settings-cookies-page'));
     page.prefs = {
-      profile: {
-        cookie_controls_mode: {value: 0},
-        block_third_party_cookies: {value: false},
+      generated: {
+        cookie_session_only: {value: false},
+        cookie_primary_setting:
+            {type: chrome.settingsPrivate.PrefType.NUMBER, value: 0},
       },
     };
     document.body.appendChild(page);
@@ -409,16 +239,4 @@
   test('BlockThirdPartyRadio_Hidden', function() {
     assertFalse(isChildVisible(page, '#blockThirdPartyIncognito'));
   });
-
-  test('BlockThirdPartyRadio_NotSelected', async function() {
-    // Create a preference state that would select the removed radio button
-    // and ensure the correct radio button is instead selected.
-    page.set(
-        'prefs.profile.cookie_controls_mode.value',
-        CookieControlsMode.INCOGNITO_ONLY);
-    flush();
-    await siteSettingsBrowserProxy.whenCalled('getDefaultValueForContentType');
-
-    assertTrue(page.$$('#allowAll').checked);
-  });
 });
diff --git a/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js b/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
index 46d11972..5e77154 100644
--- a/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
@@ -291,6 +291,29 @@
 });
 
 // eslint-disable-next-line no-var
+var CrSettingsSafetyCheckChromeCleanerV3Test = class extends CrSettingsV3BrowserTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://settings/test_loader.html?module=settings/safety_check_chrome_cleaner_test.js';
+  }
+
+  /** @override */
+  get featureListInternal() {
+    return {
+      enabled: [
+        'features::kPrivacySettingsRedesign',
+      ],
+    };
+  }
+};
+
+GEN('#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)');
+TEST_F('CrSettingsSafetyCheckChromeCleanerV3Test', 'All', function() {
+  mocha.run();
+});
+GEN('#endif  // defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)');
+
+// eslint-disable-next-line no-var
 var CrSettingsSiteListV3Test = class extends CrSettingsV3BrowserTest {
   /** @override */
   get browsePreload() {
diff --git a/chrome/test/data/webui/settings/passwords_section_test.js b/chrome/test/data/webui/settings/passwords_section_test.js
index 1db71a0..f5eb555 100644
--- a/chrome/test/data/webui/settings/passwords_section_test.js
+++ b/chrome/test/data/webui/settings/passwords_section_test.js
@@ -9,11 +9,12 @@
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {getToastManager} from 'chrome://settings/lazy_load.js';
-import {MultiStorePasswordUiEntry, PasswordManagerImpl, PasswordManagerProxy, Router, routes, SettingsPluralStringProxyImpl} from 'chrome://settings/settings.js';
+import {MultiStorePasswordUiEntry, PasswordManagerImpl, PasswordManagerProxy, ProfileInfoBrowserProxyImpl, Router, routes, SettingsPluralStringProxyImpl} from 'chrome://settings/settings.js';
 import {createExceptionEntry, createMultiStorePasswordEntry, createPasswordEntry, makeCompromisedCredential, makePasswordCheckStatus, PasswordSectionElementFactory} from 'chrome://test/settings/passwords_and_autofill_fake_data.js';
 import {runCancelExportTest, runExportFlowErrorRetryTest, runExportFlowErrorTest, runExportFlowFastTest, runExportFlowSlowTest, runFireCloseEventAfterExportCompleteTest,runStartExportTest} from 'chrome://test/settings/passwords_export_test.js';
 import {getSyncAllPrefs, simulateStoredAccounts, simulateSyncStatus} from 'chrome://test/settings/sync_test_util.m.js';
 import {TestPasswordManagerProxy} from 'chrome://test/settings/test_password_manager_proxy.js';
+import {TestProfileInfoBrowserProxy} from 'chrome://test/settings/test_profile_info_browser_proxy.m.js';
 import {TestPluralStringProxy} from 'chrome://test/test_plural_string_proxy.js';
 import {eventToPromise} from 'chrome://test/test_util.m.js';
 
@@ -990,7 +991,9 @@
           exportDialog, passwordManager);
     });
 
-    test('signOutHidesAccountStorageOptInButtons', function() {
+    // Tests that the opt-in/opt-out buttons appear for signed-in (non-sync)
+    // users and that the description changes accordingly.
+    test('changeOptInButtonsBasedOnSignInAndAccountStorageOptIn', function() {
       // Feature flag enabled.
       loadTimeData.overrideValues({enableAccountStorage: true});
 
@@ -1014,6 +1017,9 @@
           isDisplayed(passwordsSection.$.accountStorageButtonsContainer));
       assertTrue(isDisplayed(passwordsSection.$.optInToAccountStorageButton));
       assertFalse(isDisplayed(passwordsSection.$.optOutOfAccountStorageButton));
+      assertEquals(
+          passwordsSection.i18n('optInAccountStorageBody'),
+          passwordsSection.$.accountStorageBody.innerText);
 
       // Opt in.
       passwordManager.setIsOptedInForAccountStorageAndNotify(true);
@@ -1021,6 +1027,9 @@
           isDisplayed(passwordsSection.$.accountStorageButtonsContainer));
       assertFalse(isDisplayed(passwordsSection.$.optInToAccountStorageButton));
       assertTrue(isDisplayed(passwordsSection.$.optOutOfAccountStorageButton));
+      assertEquals(
+          passwordsSection.i18n('optOutAccountStorageBody'),
+          passwordsSection.$.accountStorageBody.innerText);
 
       // Sign out
       simulateStoredAccounts([]);
@@ -1028,6 +1037,43 @@
           isDisplayed(passwordsSection.$.accountStorageButtonsContainer));
     });
 
+    // Tests that profile picture and account mail address are shown for the
+    // opt-in buttons.
+    test('showAccountImageAndEmailOnOptInButtons', function() {
+      // Create fake profile data.
+      const profileInfoBrowserProxy = new TestProfileInfoBrowserProxy();
+      ProfileInfoBrowserProxyImpl.instance_ = profileInfoBrowserProxy;
+      const iconDataUrl = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEA' +
+          'LAAAAAABAAEAAAICTAEAOw==';
+
+      // Feature flag enabled.
+      loadTimeData.overrideValues({enableAccountStorage: true});
+
+      const passwordsSection =
+          elementFactory.createPasswordsSection(passwordManager, [], []);
+
+      // Sync is disabled and the user is initially signed out.
+      simulateSyncStatus({signedIn: false});
+      const isDisplayed = element => !!element && !element.hidden;
+      assertFalse(
+          isDisplayed(passwordsSection.$.accountStorageButtonsContainer));
+
+      // User signs in which updates the profile info.
+      simulateStoredAccounts([{
+        fullName: 'john doe',
+        givenName: 'john',
+        email: 'john@gmail.com',
+      }]);
+      webUIListenerCallback(
+          'profile-info-changed', {name: 'john doe', iconUrl: iconDataUrl});
+      flush();
+
+      passwordManager.setIsOptedInForAccountStorageAndNotify(false);
+      assertEquals('john@gmail.com', passwordsSection.$.accountEmail.innerText);
+      const bg = passwordsSection.$.profileIcon.style.backgroundImage;
+      assertTrue(bg.includes(iconDataUrl));
+    });
+
     test('enablingSyncHidesAccountStorageOptInButtons', function() {
       // Feature flag enabled.
       loadTimeData.overrideValues({enableAccountStorage: true});
diff --git a/chrome/test/data/webui/settings/safety_check_chrome_cleaner_test.js b/chrome/test/data/webui/settings/safety_check_chrome_cleaner_test.js
new file mode 100644
index 0000000..889a505
--- /dev/null
+++ b/chrome/test/data/webui/settings/safety_check_chrome_cleaner_test.js
@@ -0,0 +1,207 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// clang-format off
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {MetricsBrowserProxyImpl, Router, routes, SafetyCheckCallbackConstants, SafetyCheckChromeCleanerStatus, SafetyCheckIconStatus, SafetyCheckInteractions} from 'chrome://settings/settings.js';
+
+import {assertEquals, assertFalse, assertTrue} from '../chai_assert.js';
+
+import {TestMetricsBrowserProxy} from './test_metrics_browser_proxy.js';
+
+// clang-format on
+
+const testDisplayString = 'Test display string';
+
+/**
+ * Fire a safety check Chrome cleaner event.
+ * @param {SafetyCheckChromeCleanerStatus} state
+ */
+function fireSafetyCheckChromeCleanerEvent(state) {
+  const event = {};
+  event.newState = state;
+  event.displayString = testDisplayString;
+  webUIListenerCallback(
+      SafetyCheckCallbackConstants.CHROME_CLEANER_CHANGED, event);
+}
+
+/**
+ * Verify that the safety check child inside the page has been configured as
+ * specified.
+ * @param {!{
+ *   page: !PolymerElement,
+ *   iconStatus: !SafetyCheckIconStatus,
+ *   label: string,
+ *   buttonLabel: (string|undefined),
+ *   buttonAriaLabel: (string|undefined),
+ *   buttonClass: (string|undefined),
+ *   managedIcon: (boolean|undefined),
+ * }} destructured1
+ */
+function assertSafetyCheckChild({
+  page,
+  iconStatus,
+  label,
+  buttonLabel,
+  buttonAriaLabel,
+  buttonClass,
+  managedIcon
+}) {
+  const safetyCheckChild = page.$$('#safetyCheckChild');
+  assertTrue(safetyCheckChild.iconStatus === iconStatus);
+  assertTrue(safetyCheckChild.label === label);
+  assertTrue(safetyCheckChild.subLabel === testDisplayString);
+  assertTrue(!buttonLabel || safetyCheckChild.buttonLabel === buttonLabel);
+  assertTrue(
+      !buttonAriaLabel || safetyCheckChild.buttonAriaLabel === buttonAriaLabel);
+  assertTrue(!buttonClass || safetyCheckChild.buttonClass === buttonClass);
+  assertTrue(!!managedIcon === !!safetyCheckChild.managedIcon);
+}
+
+suite('SafetyCheckChromeCleanerUiTests', function() {
+  /** @type {?TestMetricsBrowserProxy} */
+  let metricsBrowserProxy = null;
+
+  /** @type {!SettingsSafetyCheckExtensionsChildElement} */
+  let page;
+
+  setup(function() {
+    metricsBrowserProxy = new TestMetricsBrowserProxy();
+    MetricsBrowserProxyImpl.instance_ = metricsBrowserProxy;
+
+    document.body.innerHTML = '';
+    page = /** @type {!SettingsSafetyCheckExtensionsChildElement} */ (
+        document.createElement('settings-safety-check-chrome-cleaner-child'));
+    document.body.appendChild(page);
+    flush();
+  });
+
+  teardown(function() {
+    page.remove();
+  });
+
+  /** @return {!Promise} */
+  async function expectChromeCleanerRouteButtonClickActions() {
+    // User clicks review extensions button.
+    page.$$('#safetyCheckChild').$$('#button').click();
+    // // TODO(crbug.com/1087263): Ensure UMA is logged.
+    // Ensure the correct Settings page is shown.
+    assertEquals(routes.CHROME_CLEANUP, Router.getInstance().getCurrentRoute());
+  }
+
+  test('chromeCleanerCheckingUiTest', function() {
+    fireSafetyCheckChromeCleanerEvent(SafetyCheckChromeCleanerStatus.CHECKING);
+    flush();
+    assertSafetyCheckChild({
+      page: page,
+      iconStatus: SafetyCheckIconStatus.RUNNING,
+      label: 'Unwanted software protection',
+    });
+  });
+
+  test('chromeCleanerCSafeStatesUiTest', function() {
+    for (const state of Object.values(SafetyCheckChromeCleanerStatus)) {
+      switch (state) {
+        case SafetyCheckChromeCleanerStatus.INITIAL:
+        case SafetyCheckChromeCleanerStatus.REPORTER_FOUND_NOTHING:
+        case SafetyCheckChromeCleanerStatus.SCANNING_FOUND_NOTHING:
+        case SafetyCheckChromeCleanerStatus.CLEANING_SUCCEEDED:
+        case SafetyCheckChromeCleanerStatus.REPORTER_RUNNING:
+        case SafetyCheckChromeCleanerStatus.SCANNING:
+          fireSafetyCheckChromeCleanerEvent(state);
+          flush();
+          assertSafetyCheckChild({
+            page: page,
+            iconStatus: SafetyCheckIconStatus.SAFE,
+            label: 'Unwanted software protection',
+          });
+          break;
+        default:
+          // Not covered by this test.
+          break;
+      }
+    }
+  });
+
+  test('chromeCleanerInfoWithDefaultButtonStatesUiTest', function() {
+    for (const state of Object.values(SafetyCheckChromeCleanerStatus)) {
+      switch (state) {
+        case SafetyCheckChromeCleanerStatus.REPORTER_FAILED:
+        case SafetyCheckChromeCleanerStatus.SCANNING_FAILED:
+        case SafetyCheckChromeCleanerStatus.CONNECTION_LOST:
+        case SafetyCheckChromeCleanerStatus.CLEANING_FAILED:
+        case SafetyCheckChromeCleanerStatus.CLEANER_DOWNLOAD_FAILED:
+        case SafetyCheckChromeCleanerStatus.CLEANING:
+          fireSafetyCheckChromeCleanerEvent(state);
+          flush();
+          assertSafetyCheckChild({
+            page: page,
+            iconStatus: SafetyCheckIconStatus.INFO,
+            label: 'Unwanted software protection',
+            buttonLabel: 'Review',
+            buttonAriaLabel: 'Review unwanted software',
+          });
+          expectChromeCleanerRouteButtonClickActions();
+          break;
+        default:
+          // Not covered by this test.
+          break;
+      }
+    }
+  });
+
+  test('chromeCleanerWarningStatesUiTest', function() {
+    for (const state of Object.values(SafetyCheckChromeCleanerStatus)) {
+      switch (state) {
+        case SafetyCheckChromeCleanerStatus.USER_DECLINED_CLEANUP:
+        case SafetyCheckChromeCleanerStatus.INFECTED:
+          fireSafetyCheckChromeCleanerEvent(state);
+          flush();
+          assertSafetyCheckChild({
+            page: page,
+            iconStatus: SafetyCheckIconStatus.WARNING,
+            label: 'Unwanted software protection',
+            buttonLabel: 'Review',
+            buttonAriaLabel: 'Review unwanted software',
+            buttonClass: 'action-button',
+          });
+          expectChromeCleanerRouteButtonClickActions();
+          break;
+        default:
+          // Not covered by this test.
+          break;
+      }
+    }
+  });
+
+  test('chromeCleanerRebootRequiredUiTest', function() {
+    fireSafetyCheckChromeCleanerEvent(
+        SafetyCheckChromeCleanerStatus.REBOOT_REQUIRED);
+    flush();
+    assertSafetyCheckChild({
+      page: page,
+      iconStatus: SafetyCheckIconStatus.INFO,
+      label: 'Unwanted software protection',
+      buttonLabel: 'Restart computer',
+      buttonAriaLabel: 'Restart computer',
+      buttonClass: 'action-button',
+    });
+    // User clicks review extensions button.
+    page.$$('#safetyCheckChild').$$('#button').click();
+    // TODO(crbug.com/1087263): Ensure UMA is logged.
+    // TODO(crbug.com/1087263): Ensure reboot call is done.
+  });
+
+  test('chromeCleanerDisabledByAdminUiTest', function() {
+    fireSafetyCheckChromeCleanerEvent(
+        SafetyCheckChromeCleanerStatus.DISABLED_BY_ADMIN);
+    flush();
+    assertSafetyCheckChild({
+      page: page,
+      iconStatus: SafetyCheckIconStatus.INFO,
+      label: 'Unwanted software protection',
+    });
+  });
+});
diff --git a/chrome/updater/server/mac/service_delegate.mm b/chrome/updater/server/mac/service_delegate.mm
index 11e37a3c..2f1a9171 100644
--- a/chrome/updater/server/mac/service_delegate.mm
+++ b/chrome/updater/server/mac/service_delegate.mm
@@ -107,10 +107,8 @@
 
   auto sccb = base::BindRepeating(base::RetainBlock(^(
       updater::UpdateService::UpdateState state) {
-    base::scoped_nsobject<NSString> version(@"");
-    if (state.next_version.IsValid()) {
-      version.reset(base::SysUTF8ToNSString(state.next_version.GetString()));
-    }
+    NSString* version = base::SysUTF8ToNSString(
+        state.next_version.IsValid() ? state.next_version.GetString() : "");
 
     base::scoped_nsobject<CRUUpdateStateStateWrapper> updateStateStateWrapper(
         [[CRUUpdateStateStateWrapper alloc]
@@ -125,7 +123,7 @@
         [[CRUUpdateStateWrapper alloc]
               initWithAppId:base::SysUTF8ToNSString(state.app_id)
                       state:updateStateStateWrapper.get()
-                    version:version.get()
+                    version:version
             downloadedBytes:state.downloaded_bytes
                  totalBytes:state.total_bytes
             installProgress:state.install_progress
@@ -153,10 +151,8 @@
 
   auto sccb = base::BindRepeating(base::RetainBlock(^(
       updater::UpdateService::UpdateState state) {
-    base::scoped_nsobject<NSString> version(@"");
-    if (state.next_version.IsValid()) {
-      version.reset(base::SysUTF8ToNSString(state.next_version.GetString()));
-    }
+    NSString* version = base::SysUTF8ToNSString(
+        state.next_version.IsValid() ? state.next_version.GetString() : "");
 
     base::scoped_nsobject<CRUUpdateStateStateWrapper> updateStateStateWrapper(
         [[CRUUpdateStateStateWrapper alloc]
@@ -171,7 +167,7 @@
         [[CRUUpdateStateWrapper alloc]
               initWithAppId:base::SysUTF8ToNSString(state.app_id)
                       state:updateStateStateWrapper.get()
-                    version:version.get()
+                    version:version
             downloadedBytes:state.downloaded_bytes
                  totalBytes:state.total_bytes
             installProgress:state.install_progress
diff --git a/chrome/updater/server/mac/update_service_wrappers.mm b/chrome/updater/server/mac/update_service_wrappers.mm
index dc33319d..267ee09 100644
--- a/chrome/updater/server/mac/update_service_wrappers.mm
+++ b/chrome/updater/server/mac/update_service_wrappers.mm
@@ -187,6 +187,8 @@
       updater::UpdateService::UpdateState::State::kNotStarted),
   kCRUUpdateStateStateCheckingForUpdates = static_cast<NSInteger>(
       updater::UpdateService::UpdateState::State::kCheckingForUpdates),
+  kCRUUPdateStateStateUpdateAvailable = static_cast<NSInteger>(
+      updater::UpdateService::UpdateState::State::kUpdateAvailable),
   kCRUUpdateStateStateDownloading = static_cast<NSInteger>(
       updater::UpdateService::UpdateState::State::kDownloading),
   kCRUUpdateStateStateInstalling = static_cast<NSInteger>(
@@ -227,6 +229,10 @@
       return
           [self initWithUpdateStateState:updater::UpdateService::UpdateState::
                                              State::kCheckingForUpdates];
+    case kCRUUPdateStateStateUpdateAvailable:
+      return
+          [self initWithUpdateStateState:updater::UpdateService::UpdateState::
+                                             State::kUpdateAvailable];
     case kCRUUpdateStateStateDownloading:
       return
           [self initWithUpdateStateState:updater::UpdateService::UpdateState::
diff --git a/chrome/updater/win/install_app.cc b/chrome/updater/win/install_app.cc
index c6b6da7..ae4214e5 100644
--- a/chrome/updater/win/install_app.cc
+++ b/chrome/updater/win/install_app.cc
@@ -432,7 +432,7 @@
   void DoInstallApp();
   void InstallComplete();
   void HandleInstallResult(const update_client::CrxUpdateItem& update_item);
-  void FlushPrefs();
+  void PrefsCommit();
 
   // Returns the thread id of the thread which owns the progress window.
   DWORD GetUIThreadID() const;
@@ -546,7 +546,7 @@
 // by calling UpdateClient::GetCrxUpdateState.
 void InstallAppController::InstallComplete() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  FlushPrefs();
+  PrefsCommit();
   update_client_ = nullptr;
 }
 
@@ -681,9 +681,9 @@
   return false;
 }
 
-void InstallAppController::FlushPrefs() {
+void InstallAppController::PrefsCommit() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  config_->GetPrefService()->SchedulePendingLossyWrites();
+  config_->GetPrefService()->CommitPendingWrite();
 }
 
 DWORD InstallAppController::GetUIThreadID() const {
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index 10539c2..fb2fc12 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -18,6 +18,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
@@ -267,7 +268,8 @@
       base::BindRepeating(&CastContentBrowserClient::GetCmaBackendFactory,
                           base::Unretained(this)),
       base::BindRepeating(&shell::CastSessionIdMap::GetSessionId),
-      content::GetUIThreadTaskRunner({}), GetMediaTaskRunner(),
+      base::CreateSingleThreadTaskRunner({content::BrowserThread::UI}),
+      GetMediaTaskRunner(),
       ServiceConnector::MakeRemote(kBrowserProcessClientId),
       BUILDFLAG(ENABLE_CAST_AUDIO_MANAGER_MIXER));
 #else
@@ -276,7 +278,8 @@
       base::BindRepeating(&CastContentBrowserClient::GetCmaBackendFactory,
                           base::Unretained(this)),
       base::BindRepeating(&shell::CastSessionIdMap::GetSessionId),
-      content::GetUIThreadTaskRunner({}), GetMediaTaskRunner(),
+      base::CreateSingleThreadTaskRunner({content::BrowserThread::UI}),
+      GetMediaTaskRunner(),
       ServiceConnector::MakeRemote(kBrowserProcessClientId),
       BUILDFLAG(ENABLE_CAST_AUDIO_MANAGER_MIXER));
 #endif  // defined(USE_ALSA)
@@ -288,8 +291,12 @@
 
 std::unique_ptr<::media::CdmFactory> CastContentBrowserClient::CreateCdmFactory(
     ::media::mojom::FrameInterfaceFactory* frame_interfaces) {
-  return std::make_unique<media::CastCdmFactory>(GetMediaTaskRunner(),
-                                                 media_resource_tracker());
+  url::Origin cdm_origin;
+  if(!frame_interfaces->GetCdmOrigin(&cdm_origin))
+    return nullptr;
+
+  return std::make_unique<media::CastCdmFactory>(
+      GetMediaTaskRunner(), cdm_origin, media_resource_tracker());
 }
 
 media::MediaCapsImpl* CastContentBrowserClient::media_caps() {
@@ -406,8 +413,8 @@
       ->Insert(extension->id(), site_instance->GetProcess()->GetID(),
                site_instance->GetId());
 
-  content::GetIOThreadTaskRunner({})->PostTask(
-      FROM_HERE, base::BindOnce(&extensions::InfoMap::RegisterExtensionProcess,
+  base::PostTask(FROM_HERE, {content::BrowserThread::IO},
+                 base::BindOnce(&extensions::InfoMap::RegisterExtensionProcess,
                                 extension_system->info_map(), extension->id(),
                                 site_instance->GetProcess()->GetID(),
                                 site_instance->GetId()));
@@ -605,8 +612,8 @@
   std::string session_id =
       CastNavigationUIData::GetSessionIdForWebContents(web_contents);
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  content::GetIOThreadTaskRunner({})->PostTask(
-      FROM_HERE,
+  base::PostTask(
+      FROM_HERE, {content::BrowserThread::IO},
       base::BindOnce(
           &CastContentBrowserClient::SelectClientCertificateOnIOThread,
           base::Unretained(this), requesting_url, session_id,
diff --git a/chromecast/browser/cast_display_configurator.cc b/chromecast/browser/cast_display_configurator.cc
index a50e70ca..afaa233 100644
--- a/chromecast/browser/cast_display_configurator.cc
+++ b/chromecast/browser/cast_display_configurator.cc
@@ -78,6 +78,20 @@
     return display::Display::ROTATE_0;
 }
 
+display::Display::Rotation RotationFromPanelOrientation(
+    display::PanelOrientation orientation) {
+  switch (orientation) {
+    case display::kNormal:
+      return display::Display::ROTATE_0;
+    case display::kRightUp:
+      return display::Display::ROTATE_90;
+    case display::kBottomUp:
+      return display::Display::ROTATE_180;
+    case display::kLeftUp:
+      return display::Display::ROTATE_270;
+  }
+}
+
 gfx::Rect GetScreenBounds(const gfx::Size& size_in_pixels,
                           display::Display::Rotation rotation) {
   switch (rotation) {
@@ -187,7 +201,7 @@
     // during the first queries to display::Screen.
     UpdateScreen(display_->display_id(), gfx::Rect(origin, native_size),
                  GetDeviceScaleFactor(native_size),
-                 GetRotationFromCommandLine());
+                 RotationFromPanelOrientation(display_->panel_orientation()));
   }
 
   delegate_->Configure(
@@ -216,7 +230,7 @@
 
     UpdateScreen(display_->display_id(), bounds,
                  GetDeviceScaleFactor(display->native_mode()->size()),
-                 GetRotationFromCommandLine());
+                 RotationFromPanelOrientation(display_->panel_orientation()));
   } else {
     LOG(FATAL) << "Failed to configure display";
   }
diff --git a/chromecast/media/cdm/cast_cdm_factory.cc b/chromecast/media/cdm/cast_cdm_factory.cc
index 8eec140..de18f632 100644
--- a/chromecast/media/cdm/cast_cdm_factory.cc
+++ b/chromecast/media/cdm/cast_cdm_factory.cc
@@ -19,9 +19,11 @@
 
 CastCdmFactory::CastCdmFactory(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+    const url::Origin& cdm_origin,
     MediaResourceTracker* media_resource_tracker)
     : media_resource_tracker_(media_resource_tracker),
-      task_runner_(task_runner) {
+      task_runner_(task_runner),
+      cdm_origin_(cdm_origin) {
   DCHECK(media_resource_tracker_);
   DCHECK(task_runner_);
 }
@@ -30,7 +32,6 @@
 
 void CastCdmFactory::Create(
     const std::string& key_system,
-    const url::Origin& security_origin,
     const ::media::CdmConfig& cdm_config,
     const ::media::SessionMessageCB& session_message_cb,
     const ::media::SessionClosedCB& session_closed_cb,
@@ -47,7 +48,7 @@
          (cast_key_system == chromecast::media::KEY_SYSTEM_WIDEVINE));
 
   scoped_refptr<chromecast::media::CastCdm> cast_cdm =
-      CreatePlatformBrowserCdm(cast_key_system, security_origin, cdm_config);
+      CreatePlatformBrowserCdm(cast_key_system, cdm_origin_, cdm_config);
 
   if (!cast_cdm) {
     LOG(INFO) << "No matching key system found: " << cast_key_system;
@@ -74,7 +75,7 @@
 
 scoped_refptr<CastCdm> CastCdmFactory::CreatePlatformBrowserCdm(
     const CastKeySystem& cast_key_system,
-    const url::Origin& security_origin,
+    const url::Origin& cdm_origin,
     const ::media::CdmConfig& cdm_config) {
   return nullptr;
 }
diff --git a/chromecast/media/cdm/cast_cdm_factory.h b/chromecast/media/cdm/cast_cdm_factory.h
index edf39f6..014457e 100644
--- a/chromecast/media/cdm/cast_cdm_factory.h
+++ b/chromecast/media/cdm/cast_cdm_factory.h
@@ -9,6 +9,7 @@
 #include "chromecast/media/base/key_systems_common.h"
 #include "chromecast/media/base/media_resource_tracker.h"
 #include "media/base/cdm_factory.h"
+#include "url/origin.h"
 
 namespace base {
 class SingleThreadTaskRunner;
@@ -27,13 +28,13 @@
  public:
   // CDM factory will use |task_runner| to initialize the CDM.
   CastCdmFactory(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+                 const url::Origin& cdm_origin,
                  MediaResourceTracker* media_resource_tracker);
   ~CastCdmFactory() override;
 
   // ::media::CdmFactory implementation:
   void Create(
       const std::string& key_system,
-      const url::Origin& security_origin,
       const ::media::CdmConfig& cdm_config,
       const ::media::SessionMessageCB& session_message_cb,
       const ::media::SessionClosedCB& session_closed_cb,
@@ -44,7 +45,7 @@
   // Provides a platform-specific BrowserCdm instance.
   virtual scoped_refptr<CastCdm> CreatePlatformBrowserCdm(
       const CastKeySystem& cast_key_system,
-      const url::Origin& security_origin,
+      const url::Origin& cdm_origin,
       const ::media::CdmConfig& cdm_config);
 
  protected:
@@ -52,6 +53,8 @@
 
  private:
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+  const url::Origin cdm_origin_;
+
   DISALLOW_COPY_AND_ASSIGN(CastCdmFactory);
 };
 
diff --git a/chromeos/components/media_app_ui/resources/js/launch.js b/chromeos/components/media_app_ui/resources/js/launch.js
index c2b5b924..72bb4bc 100644
--- a/chromeos/components/media_app_ui/resources/js/launch.js
+++ b/chromeos/components/media_app_ui/resources/js/launch.js
@@ -32,25 +32,19 @@
 let entryIndex = -1;
 
 /**
- * Token that identifies the file that is currently writable. Incremented each
- * time a new file is given focus.
- * @type {number}
- */
-let fileToken = 0;
-
-/**
- * The file currently writable.
- * @type {?FileDescriptor}
- */
-let currentlyWritableFile = null;
-
-/**
  * Reference to the directory handle that contains the first file in the most
  * recent launch event.
  * @type {?FileSystemDirectoryHandle}
  */
 let currentDirectoryHandle = null;
 
+/**
+ * Map of file tokens. Persists across new launch requests from the file
+ * manager when chrome://media-app has not been closed.
+ * @type {!Map<number, !FileSystemFileHandle>}
+ */
+const tokenMap = new Map();
+
 /** A pipe through which we can send messages to the guest frame. */
 const guestMessagePipe = new MessagePipe('chrome-untrusted://media-app');
 
@@ -73,24 +67,20 @@
 
 guestMessagePipe.registerHandler(Message.OVERWRITE_FILE, async (message) => {
   const overwrite = /** @type {OverwriteFileMessage} */ (message);
-  if (!currentlyWritableFile || overwrite.token !== fileToken) {
-    throw new Error('File not current.');
-  }
-
-  await saveBlobToFile(currentlyWritableFile.handle, overwrite.blob);
+  await saveBlobToFile(fileHandleForToken(overwrite.token), overwrite.blob);
 });
 
 guestMessagePipe.registerHandler(Message.DELETE_FILE, async (message) => {
   const deleteMsg = /** @type{DeleteFileMessage} */ (message);
-  const {file, directory} =
+  const {handle, directory} =
       assertFileAndDirectoryMutable(deleteMsg.token, 'Delete');
 
-  if (!(await isCurrentHandleInCurrentDirectory())) {
+  if (!(await isHandleInCurrentDirectory(handle))) {
     return {deleteResult: DeleteResult.FILE_MOVED};
   }
 
   // Get the name from the file reference. Handles file renames.
-  const currentFilename = (await file.handle.getFile()).name;
+  const currentFilename = (await handle.getFile()).name;
 
   await directory.removeEntry(currentFilename);
 
@@ -108,14 +98,14 @@
 /** Handler to rename the currently focused file. */
 guestMessagePipe.registerHandler(Message.RENAME_FILE, async (message) => {
   const renameMsg = /** @type{RenameFileMessage} */ (message);
-  const {file, directory} =
+  const {handle, directory} =
       assertFileAndDirectoryMutable(renameMsg.token, 'Rename');
 
   if (await filenameExistsInCurrentDirectory(renameMsg.newFilename)) {
     return {renameResult: RenameResult.FILE_EXISTS};
   }
 
-  const originalFile = await file.handle.getFile();
+  const originalFile = await handle.getFile();
   const renamedFileHandle =
       await directory.getFile(renameMsg.newFilename, {create: true});
   // Copy file data over to the new file.
@@ -127,9 +117,9 @@
 
   // Remove the old file since the new file has all the data & the new name.
   // Note even though removing an entry that doesn't exist is considered
-  // success, we first check the `currentlyWritableFile.handle` is the same as
-  // the handle for the file with that filename in the `currentDirectoryHandle`.
-  if (await isCurrentHandleInCurrentDirectory()) {
+  // success, we first check `handle` is the same as the handle for the file
+  // with that filename in the `currentDirectoryHandle`.
+  if (await isHandleInCurrentDirectory(handle)) {
     await directory.removeEntry(originalFile.name);
   }
 
@@ -175,16 +165,65 @@
   }
 
   const {handle} = await getFileFromHandle(fileSystemHandle);
-  // Note there may be no currently writable file (e.g. save from clipboard).
-  if (currentlyWritableFile &&
-      await handle.isSameEntry(currentlyWritableFile.handle)) {
-    return 'attemptedCurrentlyWritableFileOverwrite';
-  }
-
+  // Note `handle` could be the same as a `FileSystemFileHandle` that exists in
+  // `tokenMap`. Possibly even the `File` currently open. But that's OK. E.g.
+  // the next overwrite-file request will just invoke `saveBlobToFile` in the
+  // same way. Note there may be no currently writable file (e.g. save from
+  // clipboard).
   await saveBlobToFile(handle, blob);
 });
 
 /**
+ * Generator instance for unguessable tokens.
+ * @suppress {reportUnknownTypes} Typing of yield is broken (b/142881197).
+ * @type {!Generator<number>}
+ */
+const tokenGenerator = (function*() {
+  // To use the regular number type, tokens must stay below
+  // Number.MAX_SAFE_INTEGER (2^53). So stick with ~33 bits. Note we can not
+  // request more than 64kBytes from crypto.getRandomValues() at a time.
+  const randomBuffer = new Uint32Array(1000);
+  while (true) {
+    assertCast(crypto).getRandomValues(randomBuffer);
+    for (let i = 0; i < randomBuffer.length; ++i) {
+      const token = randomBuffer[i];
+      if (!tokenMap.has(token)) {
+        yield Number(token);
+      }
+    }
+  }
+})();
+
+/**
+ * Generate a file token, and persist the mapping to `handle`.
+ * @param {!FileSystemFileHandle} handle
+ * @return {number}
+ */
+function generateToken(handle) {
+  const token = tokenGenerator.next().value;
+  tokenMap.set(token, handle);
+  return token;
+}
+
+/**
+ * Returns the `FileSystemFileHandle` for the given `token`. This is
+ * "guaranteed" to succeed: tokens are only generated once a file handle has
+ * been successfully opened at least once (and determined to be "related"). The
+ * handle doesn't expire, but file system operations may fail later on.
+ * One corner case, however, is when the initial file open fails and the token
+ * gets replaced by `-1`. File operations all need to fail in that case.
+ * @param {number} token
+ * @return {!FileSystemFileHandle}
+ */
+function fileHandleForToken(token) {
+  const handle = tokenMap.get(token);
+  if (!handle) {
+    throw new DOMException(`No handle for token(${token})`, 'NotFoundError');
+  }
+  return handle;
+}
+
+/**
  * Saves the provided blob the provided fileHandle. Assumes the handle is
  * writable.
  * @param {!FileSystemFileHandle} handle
@@ -246,22 +285,10 @@
 }
 
 /**
- * Loads the current file list into the guest, enabling writes.
+ * Loads the current file list into the guest.
  * @return {!Promise<undefined>}
  */
 async function sendFilesToGuest() {
-  // Before sending to guest ensure writableFileIndex is set to be writable,
-  // also clear the old token.
-  if (currentlyWritableFile) {
-    currentlyWritableFile.token = -1;
-  }
-  if (currentFiles.length) {
-    currentlyWritableFile = currentFiles[entryIndex];
-    currentlyWritableFile.token = ++fileToken;
-  } else {
-    currentlyWritableFile = null;
-  }
-
   return sendSnapshotToGuest([...currentFiles]);  // Shallow copy.
 }
 
@@ -302,33 +329,31 @@
  * the file to be mutated is incorrect.
  * @param {number} editFileToken
  * @param {string} operation
- * @return {{file: !FileDescriptor, directory: !FileSystemDirectoryHandle}}
+ * @return {{handle: !FileSystemFileHandle, directory:
+ *     !FileSystemDirectoryHandle}}
  */
 function assertFileAndDirectoryMutable(editFileToken, operation) {
-  if (!currentlyWritableFile || editFileToken !== fileToken) {
-    throw new Error(`${operation} failed. File not current.`);
-  }
-
   if (!currentDirectoryHandle) {
     throw new Error(`${operation} failed. File without launch directory.`);
   }
-  return {file: currentlyWritableFile, directory: currentDirectoryHandle};
+
+  return {
+    handle: fileHandleForToken(editFileToken),
+    directory: currentDirectoryHandle
+  };
 }
 
 /**
- * Returns whether `currentlyWritableFile.handle` is in`currentDirectoryHandle`.
- * Prevents mutating the wrong file or a file that doesn't exist.
+ * Returns whether `handle` is in `currentDirectoryHandle`. Prevents mutating a
+ * file that doesn't exist.
+ * @param {!FileSystemFileHandle} handle
  * @return {!Promise<!boolean>}
  */
-async function isCurrentHandleInCurrentDirectory() {
-  if (!currentlyWritableFile) {
-    return false;
-  }
+async function isHandleInCurrentDirectory(handle) {
   // Get the name from the file reference. Handles file renames.
-  const currentFilename = (await currentlyWritableFile.handle.getFile()).name;
+  const currentFilename = (await handle.getFile()).name;
   const fileHandle = await getFileHandleFromCurrentDirectory(currentFilename);
-  return fileHandle ? fileHandle.isSameEntry(currentlyWritableFile.handle) :
-                      false;
+  return fileHandle ? fileHandle.isSameEntry(handle) : false;
 }
 
 /**
@@ -415,6 +440,8 @@
   if (!focusFile || !focusFile.name) {
     return;
   }
+  // TODO(b/158149714): Clear out old tokens as well? Care needs to be taken to
+  // ensure any file currently open with unsaved changes can still be saved.
   currentFiles.length = 0;
   for await (const /** !FileSystemHandle */ handle of directory.getEntries()) {
     if (!handle.isFile) {
@@ -432,7 +459,11 @@
 
     // Only allow traversal of related file types.
     if (entry && isFileRelated(focusFile, entry.file)) {
-      currentFiles.push({token: -1, file: entry.file, handle: entry.handle});
+      currentFiles.push({
+        token: generateToken(entry.handle),
+        file: entry.file,
+        handle: entry.handle,
+      });
     }
   }
   const name = focusFile.name;
diff --git a/chromeos/components/media_app_ui/test/driver.js b/chromeos/components/media_app_ui/test/driver.js
index 363d5a13..89617bb 100644
--- a/chromeos/components/media_app_ui/test/driver.js
+++ b/chromeos/components/media_app_ui/test/driver.js
@@ -64,6 +64,9 @@
   constructor(/** !Blob= */ data = new Blob()) {
     this.data = data;
 
+    /** @type {!Array<!{position: number, size: (number|undefined)}>} */
+    this.writes = [];
+
     /** @type {function(!Blob)} */
     this.resolveClose;
 
@@ -74,6 +77,7 @@
   /** @override */
   async write(data) {
     const position = 0;  // Assume no seeks.
+    this.writes.push({position, size: data.size});
     this.data = new Blob([
       this.data.slice(0, position),
       data,
@@ -129,6 +133,9 @@
 
     /** @type {!string} */
     this.type = type;
+
+    /** @type {?DOMException} */
+    this.nextCreateWritableError;
   }
   /** @override */
   createWriter(options) {
@@ -136,6 +143,9 @@
   }
   /** @override */
   async createWritable(options) {
+    if (this.nextCreateWritableError) {
+      throw this.nextCreateWritableError;
+    }
     this.lastWritable = new FakeWritableFileStream();
     return this.lastWritable;
   }
@@ -181,7 +191,7 @@
    * Helper to get all entries as File.
    * @return {!Array<!File>}
    */
-  getFilesSync(index) {
+  getFilesSync() {
     return this.files.map(f => f.getFileSync());
   }
   /** @override */
@@ -353,3 +363,12 @@
   }
   return null;
 }
+
+/**
+ * Puts the app into valid but "unexpected" state for it to be in after handling
+ * a launch. Currently this restores part of the app state to what it would be
+ * on a launch from the icon (i.e. no launch files).
+ */
+function simulateLosingAccessToDirectory() {
+  currentDirectoryHandle = null;
+}
diff --git a/chromeos/components/media_app_ui/test/media_app_ui_browsertest.js b/chromeos/components/media_app_ui/test/media_app_ui_browsertest.js
index f5040a0..4ea786d 100644
--- a/chromeos/components/media_app_ui/test/media_app_ui_browsertest.js
+++ b/chromeos/components/media_app_ui/test/media_app_ui_browsertest.js
@@ -155,6 +155,22 @@
   testDone();
 });
 
+// Tests that a regular launch for multiple images succeeds, and the files get
+// distinct token mappings.
+TEST_F('MediaAppUIBrowserTest', 'MultipleFileHaveTokens', async () => {
+  const directory = await launchWithFiles(
+      [await createTestImageFile(), await createTestImageFile()]);
+
+  assertEquals(currentFiles.length, 2);
+  assertGE(currentFiles[0].token, 0);
+  assertGE(currentFiles[1].token, 0);
+  assertNotEquals(currentFiles[0].token, currentFiles[1].token);
+  assertEquals(fileHandleForToken(currentFiles[0].token), directory.files[0]);
+  assertEquals(fileHandleForToken(currentFiles[1].token), directory.files[1]);
+
+  testDone();
+});
+
 // Tests that we show error UX when trying to launch an unopenable file.
 TEST_F('MediaAppUIBrowserTest', 'LaunchUnopenableFile', async () => {
   const mockFileHandle =
@@ -375,11 +391,11 @@
 // in the untrusted context. Ensures it correctly updates the file handle owned
 // by the privileged context.
 TEST_F('MediaAppUIBrowserTest', 'OverwriteOriginalIPC', async () => {
-  const handle = new FakeFileSystemFileHandle();
-  await loadFile(await createTestImageFile(), handle);
+  const directory = await launchWithFiles([await createTestImageFile()]);
+  const handle = directory.files[0];
 
   // Write should not be called initially.
-  assertEquals(0, handle.lastWritable.data.size);
+  assertEquals(handle.lastWritable.writes.length, 0);
 
   const message = {overwriteLastFile: 'Foo'};
   const testResponse = await guestMessagePipe.sendMessage('test', message);
@@ -387,6 +403,9 @@
 
   assertEquals(testResponse.testQueryResult, 'overwriteOriginal resolved');
   assertEquals(await writeResult.text(), 'Foo');
+  assertEquals(handle.lastWritable.writes.length, 1);
+  assertDeepEquals(
+      handle.lastWritable.writes[0], {position: 0, size: 'Foo'.length});
   testDone();
 });
 
@@ -397,10 +416,15 @@
   guestMessagePipe.logClientError = error => console.log(JSON.stringify(error));
   guestMessagePipe.rethrowErrors = false;
 
-  const handle = new FakeFileSystemFileHandle();
-  await loadFile(await createTestImageFile(), handle);
-  // Force Error by forcing `fileToken` in launch.js to be out of sync.
-  fileToken = -1;
+  const directory = await launchWithFiles([await createTestImageFile()]);
+
+  // Note createWritable() throws DOMException, which does not have a stack, but
+  // in this test we want to test capture of stacks in the trusted context, so
+  // throw an error (made "here", so MediaAppUIBrowserTest is in the stack).
+  const error = new Error('Fake NotAllowedError for CrossContextErrors test.');
+  error.name = 'NotAllowedError';
+  directory.files[0].nextCreateWritableError = error;
+
   let caughtError = {};
 
   try {
@@ -410,8 +434,8 @@
     caughtError = e;
   }
 
-  assertEquals(caughtError.name, 'Error');
-  assertEquals(caughtError.message, 'test: overwrite-file: File not current.');
+  assertEquals(caughtError.name, 'NotAllowedError');
+  assertEquals(caughtError.message, `test: overwrite-file: ${error.message}`);
   assertMatchErrorStack(caughtError.stack, [
     // Error stack of the untrusted & test context.
     'at MessagePipe.sendMessage \\(chrome-untrusted:',
@@ -420,10 +444,8 @@
     'at async MessagePipe.callHandlerForMessageType_ \\(chrome-untrusted:',
     // Error stack of the trusted context is appended.
     'Error from chrome:',
-    'Error: File not current.\\n    at chrome:',
-    'at MessagePipe.callHandlerForMessageType_ \\(chrome:',
-    'at MessagePipe.receiveMessage_ \\(chrome:',
-    'at MessagePipe.messageListener_ \\(chrome:',
+    'NotAllowedError: Fake NotAllowedError for CrossContextErrors test.',
+    'at MediaAppUIBrowserTest',
   ]);
   testDone();
 });
@@ -574,13 +596,10 @@
 // Tests the IPC behind the implementation of ReceivedFile.renameOriginalFile()
 // in the untrusted context.
 TEST_F('MediaAppUIBrowserTest', 'RenameOriginalIPC', async () => {
-  const firstFile = await createTestImageFile();
-  const directory = await createMockTestDirectory([firstFile]);
-  // Simulate steps taken to load a file via a launch event.
+  const directory = await launchWithFiles([await createTestImageFile()]);
   const firstFileHandle = directory.files[0];
-  await loadFile(firstFile, firstFileHandle);
-  // Set `currentDirectoryHandle` in launch.js.
-  currentDirectoryHandle = directory;
+  const firstFile = firstFileHandle.getFileSync();
+
   let testResponse;
 
   // Nothing should be deleted initially.
@@ -617,8 +636,8 @@
   // Prevent the trusted context throwing errors resulting JS errors.
   guestMessagePipe.logClientError = error => console.log(JSON.stringify(error));
   guestMessagePipe.rethrowErrors = false;
-  // Test UNKNOWN_ERROR case by making files out of sync.
-  fileToken = -1;
+  // Test UNKNOWN_ERROR case by simulating a failed directory change.
+  simulateLosingAccessToDirectory();
 
   const messageRenameNoOp = {renameLastFile: 'new_file_name_2.png'};
   testResponse = await guestMessagePipe.sendMessage('test', messageRenameNoOp);
diff --git a/chromeos/components/quick_answers/quick_answers_client.cc b/chromeos/components/quick_answers/quick_answers_client.cc
index 67ad74b..e0fc2f9 100644
--- a/chromeos/components/quick_answers/quick_answers_client.cc
+++ b/chromeos/components/quick_answers/quick_answers_client.cc
@@ -198,11 +198,13 @@
 
   delegate_->OnRequestPreprocessFinished(processed_request);
 
-  if (features::IsQuickAnswersTextAnnotatorEnabled() &&
-      processed_request.preprocessed_output.intent_type ==
-          IntentType::kUnknown) {
-    // Don't fetch answer if no intent is generated.
-    return;
+  if (features::IsQuickAnswersTextAnnotatorEnabled()) {
+    RecordIntentType(processed_request.preprocessed_output.intent_type);
+    if (processed_request.preprocessed_output.intent_type ==
+        IntentType::kUnknown) {
+      // Don't fetch answer if no intent is generated.
+      return;
+    }
   }
 
   result_loader_ = CreateResultLoader(intent_type);
diff --git a/chromeos/components/quick_answers/quick_answers_model.h b/chromeos/components/quick_answers/quick_answers_model.h
index 964cdc9..15fac972 100644
--- a/chromeos/components/quick_answers/quick_answers_model.h
+++ b/chromeos/components/quick_answers/quick_answers_model.h
@@ -51,11 +51,15 @@
 };
 
 // The predicted intent of the request.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+// Note: Enums labels are at |QuickAnswersIntentType|.
 enum class IntentType {
   kUnknown = 0,
   kUnit = 1,
   kDictionary = 2,
-  kTranslation = 3
+  kTranslation = 3,
+  kMaxValue = kTranslation
 };
 
 enum class QuickAnswerUiElementType {
diff --git a/chromeos/components/quick_answers/utils/quick_answers_metrics.cc b/chromeos/components/quick_answers/utils/quick_answers_metrics.cc
index b30b6227..ceeab22 100644
--- a/chromeos/components/quick_answers/utils/quick_answers_metrics.cc
+++ b/chromeos/components/quick_answers/utils/quick_answers_metrics.cc
@@ -16,6 +16,7 @@
 const char kQuickAnswerActiveImpression[] = "QuickAnswers.ActiveImpression";
 const char kQuickAnswerClick[] = "QuickAnswers.Click";
 const char kQuickAnswerResult[] = "QuickAnswers.Result";
+const char kQuickAnswerIntent[] = "QuickAnswers.Intent";
 const char kQuickAnswerLoadingStatus[] = "QuickAnswers.Loading.Status";
 const char kQuickAnswerLoadingDuration[] = "QuickAnswers.Loading.Duration";
 const char kQuickAnswerSelectedContentLength[] =
@@ -122,5 +123,9 @@
   base::UmaHistogramExactLinear(kQuickAnswersConsent, nth_impression,
                                 kConsentImpressionCap);
 }
+
+void RecordIntentType(IntentType intent_type) {
+  base::UmaHistogramEnumeration(kQuickAnswerIntent, intent_type);
+}
 }  // namespace quick_answers
 }  // namespace chromeos
diff --git a/chromeos/components/quick_answers/utils/quick_answers_metrics.h b/chromeos/components/quick_answers/utils/quick_answers_metrics.h
index 24c4a38..90206085 100644
--- a/chromeos/components/quick_answers/utils/quick_answers_metrics.h
+++ b/chromeos/components/quick_answers/utils/quick_answers_metrics.h
@@ -42,6 +42,9 @@
 // Record consent impression with how many times the user has seen the consent.
 void RecordConsentImpression(int nth_impression);
 
+// Record the intent generated on-device.
+void RecordIntentType(IntentType intent_type);
+
 }  // namespace quick_answers
 }  // namespace chromeos
 
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc
index a655c15..1a642a5 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/chromeos/constants/chromeos_features.cc
@@ -86,7 +86,7 @@
 
 // Enables or disables Crostini port forwarding.
 const base::Feature kCrostiniPortForwarding{"CrostiniPortForwarding",
-                                            base::FEATURE_DISABLED_BY_DEFAULT};
+                                            base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables or disables Crostini Disk Resizing.
 const base::Feature kCrostiniDiskResizing{"CrostiniDiskResizing",
diff --git a/chromeos/services/assistant/assistant_manager_service_impl_unittest.cc b/chromeos/services/assistant/assistant_manager_service_impl_unittest.cc
index a276e0d..76e4d841 100644
--- a/chromeos/services/assistant/assistant_manager_service_impl_unittest.cc
+++ b/chromeos/services/assistant/assistant_manager_service_impl_unittest.cc
@@ -104,6 +104,11 @@
   ~AssistantAlarmTimerControllerMock() override = default;
 
   // ash::AssistantAlarmTimerController:
+  MOCK_METHOD((const ash::AssistantAlarmTimerModel*),
+              GetModel,
+              (),
+              (const, override));
+
   MOCK_METHOD(void,
               OnTimerStateChanged,
               (std::vector<ash::AssistantTimerPtr>),
diff --git a/chromeos/services/assistant/public/mojom/assistant_notification.mojom b/chromeos/services/assistant/public/mojom/assistant_notification.mojom
index 078ecef..6d3d724d 100644
--- a/chromeos/services/assistant/public/mojom/assistant_notification.mojom
+++ b/chromeos/services/assistant/public/mojom/assistant_notification.mojom
@@ -19,6 +19,14 @@
   bool remove_notification_on_click = true;
 };
 
+// Enumeration of possible notification priorities.
+// NOTE: This enum maps to a subset of message_center::NotificationPriority.
+enum AssistantNotificationPriority {
+  kLow,     // See message_center::NotificationPriority::LOW_PRIORITY.
+  kDefault, // See message_center::NotificationPriority::DEFAULT_PRIORITY.
+  kHigh,    // See message_center::NotificationPriority::HIGH_PRIORITY.
+};
+
 // Models an Assistant notification.
 struct AssistantNotification {
   // Title of the notification.
@@ -50,8 +58,9 @@
   // Obfuscated Gaia id of the intended recipient of the user.
   string obfuscated_gaia_id;
 
-  // Whether this notification can turn on the display if it was off.
-  bool is_high_priority = false;
+  // Priority for the notification. This affects whether or not the notification
+  // will pop up and/or have the capability to wake the display if it was off.
+  AssistantNotificationPriority priority = kDefault;
 
   // When the notification should expire.
   // Expressed as milliseconds since Unix Epoch.
diff --git a/components/arc/net/OWNERS b/components/arc/net/OWNERS
new file mode 100644
index 0000000..522f9d4
--- /dev/null
+++ b/components/arc/net/OWNERS
@@ -0,0 +1,3 @@
+hugobenichi@google.com
+
+# COMPONENT: Platform>Apps>ARC
diff --git a/components/autofill/content/browser/risk/fingerprint.cc b/components/autofill/content/browser/risk/fingerprint.cc
index 35475b3..b7aa9f45 100644
--- a/components/autofill/content/browser/risk/fingerprint.cc
+++ b/components/autofill/content/browser/risk/fingerprint.cc
@@ -51,6 +51,7 @@
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
 #include "ui/gfx/geometry/rect.h"
+#include "url/gurl.h"
 
 #if BUILDFLAG(ENABLE_PLUGINS)
 #include "content/public/browser/plugin_service.h"
@@ -316,7 +317,7 @@
   content::GetDeviceService().BindGeolocationContext(
       geolocation_context_.BindNewPipeAndPassReceiver());
   geolocation_context_->BindGeolocation(
-      geolocation_.BindNewPipeAndPassReceiver());
+      geolocation_.BindNewPipeAndPassReceiver(), GURL::EmptyGURL());
   geolocation_->SetHighAccuracy(false);
   geolocation_->QueryNextPosition(
       base::BindOnce(&FingerprintDataLoader::OnGotGeoposition,
diff --git a/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc b/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc
index 3fa237a..9612abc 100644
--- a/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc
+++ b/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc
@@ -26,7 +26,7 @@
   auto* field_error = client_status->mutable_details()
                           ->mutable_autofill_error_info()
                           ->add_autofill_field_error();
-  *field_error->mutable_field() = required_field.selector.ToProto();
+  *field_error->mutable_field() = required_field.selector.proto;
   field_error->set_value_expression(required_field.value_expression);
   return field_error;
 }
diff --git a/components/autofill_assistant/browser/actions/generate_password_for_form_field_action_unittest.cc b/components/autofill_assistant/browser/actions/generate_password_for_form_field_action_unittest.cc
index e22d081..df974c8 100644
--- a/components/autofill_assistant/browser/actions/generate_password_for_form_field_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/generate_password_for_form_field_action_unittest.cc
@@ -63,7 +63,7 @@
   GeneratePasswordForFormFieldProto* generate_password_proto =
       proto_.mutable_generate_password_for_form_field();
   *generate_password_proto->mutable_element() =
-      Selector({kFakeSelector}).MustBeVisible().ToProto();
+      Selector({kFakeSelector}).MustBeVisible().proto;
   generate_password_proto->set_memory_key(kMemoryKeyForGeneratedPassword);
 
   Selector fake_selector = Selector({kFakeSelector}).MustBeVisible();
diff --git a/components/autofill_assistant/browser/actions/set_attribute_action.cc b/components/autofill_assistant/browser/actions/set_attribute_action.cc
index a1a8ceb..b49213d 100644
--- a/components/autofill_assistant/browser/actions/set_attribute_action.cc
+++ b/components/autofill_assistant/browser/actions/set_attribute_action.cc
@@ -16,7 +16,6 @@
 SetAttributeAction::SetAttributeAction(ActionDelegate* delegate,
                                        const ActionProto& proto)
     : Action(delegate, proto) {
-  DCHECK_GT(proto_.set_attribute().element().selectors_size(), 0);
   DCHECK_GT(proto_.set_attribute().attribute_size(), 0);
 }
 
diff --git a/components/autofill_assistant/browser/actions/set_form_field_value_action.cc b/components/autofill_assistant/browser/actions/set_form_field_value_action.cc
index c628e83..4e246453 100644
--- a/components/autofill_assistant/browser/actions/set_form_field_value_action.cc
+++ b/components/autofill_assistant/browser/actions/set_form_field_value_action.cc
@@ -40,7 +40,6 @@
                                                  const ActionProto& proto)
     : Action(delegate, proto) {
   DCHECK(proto_.has_set_form_value());
-  DCHECK_GT(proto_.set_form_value().element().selectors_size(), 0);
   DCHECK_GT(proto_.set_form_value().value_size(), 0);
 }
 
diff --git a/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc b/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc
index d009f4e..d90f43e 100644
--- a/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc
@@ -37,7 +37,7 @@
   void SetUp() override {
     set_form_field_proto_ = proto_.mutable_set_form_value();
     *set_form_field_proto_->mutable_element() =
-        Selector({kFakeSelector}).MustBeVisible().ToProto();
+        Selector({kFakeSelector}).MustBeVisible().proto;
     ON_CALL(mock_action_delegate_, GetUserData)
         .WillByDefault(Return(&user_data_));
     ON_CALL(mock_action_delegate_, WriteUserData)
diff --git a/components/autofill_assistant/browser/event_handler.cc b/components/autofill_assistant/browser/event_handler.cc
index 886f8f9..d0233205 100644
--- a/components/autofill_assistant/browser/event_handler.cc
+++ b/components/autofill_assistant/browser/event_handler.cc
@@ -46,6 +46,9 @@
     case EventProto::kOnPopupDismissed:
       out << "kOnPopupDismissed";
       break;
+    case EventProto::kOnViewContainerCleared:
+      out << "kOnViewContainerCleared";
+      break;
     case EventProto::KIND_NOT_SET:
       break;
   }
diff --git a/components/autofill_assistant/browser/generic_ui.proto b/components/autofill_assistant/browser/generic_ui.proto
index b0b3d0f7..e5e93afd 100644
--- a/components/autofill_assistant/browser/generic_ui.proto
+++ b/components/autofill_assistant/browser/generic_ui.proto
@@ -49,6 +49,8 @@
     SetViewVisibilityProto set_view_visibility = 11;
     SetViewEnabledProto set_view_enabled = 12;
     ShowGenericUiPopupProto show_generic_popup = 13;
+    CreateNestedGenericUiProto create_nested_ui = 14;
+    ClearViewContainerProto clear_view_container = 15;
   }
   // Optional model identifier pointing to a single boolean. If set, the
   // callback will only be invoked if the condition is true.
@@ -62,6 +64,7 @@
     OnUserActionCalled on_user_action_called = 3;
     OnTextLinkClickedProto on_text_link_clicked = 4;
     OnPopupDismissedProto on_popup_dismissed = 5;
+    OnViewContainerClearedProto on_view_container_cleared = 6;
   }
 }
 
@@ -96,6 +99,13 @@
   optional string popup_identifier = 1;
 }
 
+// Event which is called whenever |view_identifier| was cleared with a
+// |ClearViewContainer| interaction.
+message OnViewContainerClearedProto {
+  // The view container that was cleared.
+  optional string view_identifier = 1;
+}
+
 // Callback that writes the specified value to |model_identifier|.
 message SetModelValueProto {
   // The model identifier to write to.
@@ -358,3 +368,27 @@
   // Whether the view should be enabled or not. Must point to a single boolean.
   optional ValueReferenceProto enabled = 2;
 }
+
+// Creates new UI and interactions, i.e., a nested instance and attaches it to
+// |parent_view_identifier|. Nested UI instances have their own view layout and
+// interactions, but share the same model with their parent. All interactions
+// between ancestor and descendant UIs must pass through the user model, as
+// neither can directly reference views or interactions of the other.
+//
+// Use |ClearViewContainerProto| on a nested UI's view parent to detach and
+// destroy the nested UI.
+message CreateNestedGenericUiProto {
+  // Identifier for the newly created instance.
+  optional string generic_ui_identifier = 1;
+  // The UI to create.
+  optional GenericUserInterfaceProto generic_ui = 2;
+  // The view identifier of the parent to attach (=append) this UI to.
+  optional string parent_view_identifier = 3;
+}
+
+// Removes all views from the target view container. Nested UI instances
+// attached to |view_identifier| will be destroyed.
+message ClearViewContainerProto {
+  // The view container to clear.
+  optional string view_identifier = 1;
+}
diff --git a/components/autofill_assistant/browser/selector.cc b/components/autofill_assistant/browser/selector.cc
index bd2f66c..50adef4f 100644
--- a/components/autofill_assistant/browser/selector.cc
+++ b/components/autofill_assistant/browser/selector.cc
@@ -8,44 +8,184 @@
 
 namespace autofill_assistant {
 
+namespace {
+
+bool operator<(const SelectorProto::TextFilter& a,
+               const SelectorProto::TextFilter& b) {
+  return std::make_tuple(a.re2(), a.case_sensitive()) <
+         std::make_tuple(b.re2(), b.case_sensitive());
+}
+
+bool operator<(const SelectorProto::Filter& a, const SelectorProto::Filter& b) {
+  if (a.filter_case() < b.filter_case()) {
+    return true;
+  }
+  if (a.filter_case() != b.filter_case()) {
+    return false;
+  }
+  switch (a.filter_case()) {
+    case SelectorProto::Filter::kCssSelector:
+      return a.css_selector() < b.css_selector();
+
+    case SelectorProto::Filter::kInnerText:
+      return a.inner_text() < b.inner_text();
+
+    case SelectorProto::Filter::kValue:
+      return a.value() < b.value();
+
+    case SelectorProto::Filter::kPseudoType:
+      return a.pseudo_type() < b.pseudo_type();
+
+    case SelectorProto::Filter::kPseudoElementContent:
+      if (a.pseudo_element_content().pseudo_type() <
+          b.pseudo_element_content().pseudo_type()) {
+        return true;
+      }
+      if (a.pseudo_element_content().pseudo_type() !=
+          b.pseudo_element_content().pseudo_type()) {
+        return false;
+      }
+      return a.pseudo_element_content().content() <
+             b.pseudo_element_content().content();
+
+    case SelectorProto::Filter::kBoundingBox:
+    case SelectorProto::Filter::kEnterFrame:
+    case SelectorProto::Filter::kPickOne:
+    case SelectorProto::Filter::kLabelled:
+      return false;
+
+    case SelectorProto::Filter::FILTER_NOT_SET:
+      return false;
+  }
+  return false;
+}
+
+#ifndef NDEBUG
+
+std::ostream& operator<<(std::ostream& out, PseudoType pseudo_type) {
+  return out << PseudoTypeName(pseudo_type);
+}
+
+std::ostream& operator<<(std::ostream& out,
+                         const SelectorProto::TextFilter& c) {
+  out << "/" << c.re2() << "/";
+  if (c.case_sensitive()) {
+    out << "i";
+  }
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const SelectorProto::Filter& f) {
+  switch (f.filter_case()) {
+    case SelectorProto::Filter::kEnterFrame:
+      out << "/";
+      return out;
+
+    case SelectorProto::Filter::kCssSelector:
+      out << f.css_selector();
+      return out;
+
+    case SelectorProto::Filter::kInnerText:
+      out << "innerText~=" << f.inner_text();
+      return out;
+
+    case SelectorProto::Filter::kValue:
+      out << "value~=" << f.value();
+      return out;
+
+    case SelectorProto::Filter::kPseudoType:
+      out << "::" << f.pseudo_type();
+      return out;
+
+    case SelectorProto::Filter::kPseudoElementContent:
+      out << "::" << f.pseudo_element_content().pseudo_type()
+          << "~=" << f.pseudo_element_content().content();
+      return out;
+
+    case SelectorProto::Filter::kBoundingBox:
+      out << "bounding_box";
+      return out;
+
+    case SelectorProto::Filter::kPickOne:
+      out << "pick_one";
+      return out;
+
+    case SelectorProto::Filter::kLabelled:
+      out << "labelled";
+      return out;
+
+    case SelectorProto::Filter::FILTER_NOT_SET:
+      // Either unset or set to an unsupported value. Let's assume the worse.
+      out << "INVALID";
+      return out;
+  }
+}
+#endif  // NDEBUG
+}  // namespace
+
 SelectorProto ToSelectorProto(const std::string& s) {
-  return Selector({s}).ToProto();
+  return ToSelectorProto(std::vector<std::string>{s});
+}
+
+SelectorProto ToSelectorProto(const std::vector<std::string>& s) {
+  SelectorProto proto;
+  if (!s.empty()) {
+    for (size_t i = 0; i < s.size(); i++) {
+      if (i > 0) {
+        proto.add_filters()->mutable_pick_one();
+        proto.add_filters()->mutable_enter_frame();
+      }
+      proto.add_filters()->set_css_selector(s[i]);
+    }
+  }
+  return proto;
+}
+
+std::string PseudoTypeName(PseudoType pseudo_type) {
+  switch (pseudo_type) {
+    case UNDEFINED:
+      return "undefined";
+    case FIRST_LINE:
+      return "first-line";
+    case FIRST_LETTER:
+      return "first-letter";
+    case BEFORE:
+      return "before";
+    case AFTER:
+      return "after";
+    case BACKDROP:
+      return "backdrop";
+    case SELECTION:
+      return "selection";
+    case FIRST_LINE_INHERITED:
+      return "first-line-inherited";
+    case SCROLLBAR:
+      return "scrollbar";
+    case SCROLLBAR_THUMB:
+      return "scrollbar-thumb";
+    case SCROLLBAR_BUTTON:
+      return "scrollbar-button";
+    case SCROLLBAR_TRACK:
+      return "scrollbar-track";
+    case SCROLLBAR_TRACK_PIECE:
+      return "scrollbar-track-piece";
+    case SCROLLBAR_CORNER:
+      return "scrollbar-corner";
+    case RESIZER:
+      return "resizer";
+    case INPUT_LIST_BUTTON:
+      return "input-list-button";
+
+      // Intentionally no default case to make compilation fail if a new value
+      // was added to the enum but not to this list.
+  }
 }
 
 Selector::Selector() {}
 
-Selector::Selector(const SelectorProto& proto) {
-  for (const auto& selector : proto.selectors()) {
-    selectors.emplace_back(selector);
-  }
-  must_be_visible = proto.visibility_requirement() == MUST_BE_VISIBLE;
-  inner_text_pattern = proto.inner_text_pattern();
-  inner_text_pattern_case_sensitive = proto.inner_text_pattern_case_sensitive();
-  value_pattern = proto.value_pattern();
-  value_pattern_case_sensitive = proto.value_pattern_case_sensitive();
-  pseudo_type = proto.pseudo_type();
-}
+Selector::Selector(const SelectorProto& selector_proto)
+    : proto(selector_proto) {}
 
-SelectorProto Selector::ToProto() const {
-  SelectorProto proto;
-  for (const auto& selector : selectors) {
-    proto.add_selectors(selector);
-  }
-  if (must_be_visible) {
-    proto.set_visibility_requirement(MUST_BE_VISIBLE);
-  }
-  proto.set_inner_text_pattern(inner_text_pattern);
-  proto.set_inner_text_pattern_case_sensitive(
-      inner_text_pattern_case_sensitive);
-  proto.set_value_pattern(value_pattern);
-  proto.set_value_pattern_case_sensitive(value_pattern_case_sensitive);
-  proto.set_pseudo_type(pseudo_type);
-  return proto;
-}
-
-Selector::Selector(const std::vector<std::string>& s) : selectors(s) {}
-Selector::Selector(const std::vector<std::string>& s, PseudoType p)
-    : selectors(s), pseudo_type(p) {}
 Selector::~Selector() = default;
 
 Selector::Selector(Selector&& other) = default;
@@ -54,127 +194,137 @@
 Selector& Selector::operator=(Selector&& other) = default;
 
 bool Selector::operator<(const Selector& other) const {
-  return std::tie(selectors, inner_text_pattern,
-                  inner_text_pattern_case_sensitive, value_pattern,
-                  value_pattern_case_sensitive, must_be_visible, pseudo_type) <
-         std::tie(other.selectors, other.inner_text_pattern,
-                  other.inner_text_pattern_case_sensitive, other.value_pattern,
-                  other.value_pattern_case_sensitive, other.must_be_visible,
-                  other.pseudo_type);
+  const auto& a = proto.filters();
+  const auto& b = other.proto.filters();
+  if (a.size() < b.size()) {
+    return true;
+  }
+  if (a.size() != b.size()) {
+    return false;
+  }
+  for (int i = 0; i < a.size(); i++) {
+    const SelectorProto::Filter& filter_a = a.Get(i);
+    const SelectorProto::Filter& filter_b = b.Get(i);
+    if (filter_a < filter_b) {
+      return true;
+    }
+    if (filter_b < filter_a) {
+      return false;
+    }
+  }
+  return false;
 }
 
 bool Selector::operator==(const Selector& other) const {
-  return selectors == other.selectors &&
-         inner_text_pattern == other.inner_text_pattern &&
-         inner_text_pattern_case_sensitive ==
-             other.inner_text_pattern_case_sensitive &&
-         value_pattern == other.value_pattern &&
-         value_pattern_case_sensitive == other.value_pattern_case_sensitive &&
-         must_be_visible == other.must_be_visible &&
-         pseudo_type == other.pseudo_type;
+  return !(*this < other) && !(other < *this);
+}
+
+Selector& Selector::MustBeVisible() {
+  int filter_count = proto.filters().size();
+  if (filter_count == 0 || proto.filters(filter_count - 1).has_bounding_box()) {
+    // Avoids adding duplicate visibility requirements in the common case.
+    return *this;
+  }
+  proto.add_filters()->mutable_bounding_box();
+  return *this;
 }
 
 bool Selector::empty() const {
-  return this->selectors.empty();
+  bool has_css_selector = false;
+  for (const SelectorProto::Filter& filter : proto.filters()) {
+    switch (filter.filter_case()) {
+      case SelectorProto::Filter::FILTER_NOT_SET:
+        // There must not be any unknown or invalid filters.
+        return true;
+
+      case SelectorProto::Filter::kCssSelector:
+        // There must be at least one CSS selector, since it's the only
+        // way we have of expanding the set of matches.
+        has_css_selector = true;
+        break;
+
+      default:
+        break;
+    }
+  }
+  return !has_css_selector;
 }
 
 base::Optional<std::string> Selector::ExtractSingleCssSelectorForAutofill()
     const {
-  if (pseudo_type != PseudoType::UNDEFINED || !inner_text_pattern.empty() ||
-      !value_pattern.empty()) {
+  int last_enter_frame_index = -1;
+  for (int i = proto.filters().size() - 1; i >= 0; i--) {
+    if (proto.filters(i).filter_case() == SelectorProto::Filter::kEnterFrame) {
+      last_enter_frame_index = i;
+      break;
+    }
+  }
+  std::string css_selector;
+  for (int i = last_enter_frame_index + 1; i < proto.filters().size(); i++) {
+    const SelectorProto::Filter& filter = proto.filters(i);
+    switch (filter.filter_case()) {
+      case SelectorProto::Filter::kCssSelector:
+        if (css_selector.empty()) {
+          css_selector = filter.css_selector();
+        } else {
+          VLOG(1) << __func__
+                  << " Selector with multiple CSS selectors not supported for "
+                     "autofill: "
+                  << *this;
+          return base::nullopt;
+        }
+        break;
+
+      case SelectorProto::Filter::kBoundingBox:
+      case SelectorProto::Filter::kPickOne:
+        // Ignore these; they're not relevant for the autofill use-case
+        break;
+
+      case SelectorProto::Filter::kInnerText:
+      case SelectorProto::Filter::kValue:
+      case SelectorProto::Filter::kPseudoType:
+      case SelectorProto::Filter::kPseudoElementContent:
+      case SelectorProto::Filter::kLabelled:
+        VLOG(1) << __func__
+                << " Selector feature not supported by autofill: " << *this;
+        return base::nullopt;
+
+      case SelectorProto::Filter::FILTER_NOT_SET:
+        VLOG(1) << __func__ << " Unknown filter type in: " << *this;
+        return base::nullopt;
+
+      case SelectorProto::Filter::kEnterFrame:
+        // This cannot possibly happen, since the iteration started after the
+        // last enter_frame.
+        NOTREACHED();
+        break;
+    }
+  }
+  if (css_selector.empty()) {
     VLOG(1) << __func__
-            << " Selector feature not supported by autofill: " << *this;
+            << " Selector without CSS selector not supported by autofill: "
+            << *this;
     return base::nullopt;
   }
-  if (selectors.empty()) {
-    VLOG(1) << __func__ << " Empty selector.";
-    return base::nullopt;
-  }
-  return selectors[selectors.size() - 1];
+  return css_selector;
 }
 
-std::ostream& operator<<(std::ostream& out, PseudoType pseudo_type) {
-#ifdef NDEBUG
-  return out << static_cast<int>(pseudo_type);
-#else
-  switch (pseudo_type) {
-    case UNDEFINED:
-      out << "UNDEFINED";
-      break;
-    case FIRST_LINE:
-      out << "FIRST_LINE";
-      break;
-    case FIRST_LETTER:
-      out << "FIRST_LETTER";
-      break;
-    case BEFORE:
-      out << "BEFORE";
-      break;
-    case AFTER:
-      out << "AFTER";
-      break;
-    case BACKDROP:
-      out << "BACKDROP";
-      break;
-    case SELECTION:
-      out << "SELECTION";
-      break;
-    case FIRST_LINE_INHERITED:
-      out << "FIRST_LINE_INHERITED";
-      break;
-    case SCROLLBAR:
-      out << "SCROLLBAR";
-      break;
-    case SCROLLBAR_THUMB:
-      out << "SCROLLBAR_THUMB";
-      break;
-    case SCROLLBAR_BUTTON:
-      out << "SCROLLBAR_BUTTON";
-      break;
-    case SCROLLBAR_TRACK:
-      out << "SCROLLBAR_TRACK";
-      break;
-    case SCROLLBAR_TRACK_PIECE:
-      out << "SCROLLBAR_TRACK_PIECE";
-      break;
-    case SCROLLBAR_CORNER:
-      out << "SCROLLBAR_CORNER";
-      break;
-    case RESIZER:
-      out << "RESIZER";
-      break;
-    case INPUT_LIST_BUTTON:
-      out << "INPUT_LIST_BUTTON";
-      break;
-
-      // Intentionally no default case to make compilation fail if a new value
-      // was added to the enum but not to this list.
-  }
-  return out;
-#endif
-}
 std::ostream& operator<<(std::ostream& out, const Selector& selector) {
 #ifdef NDEBUG
-  out << selector.selectors.size() << " element(s)";
+  out << selector.proto.filters().size() << " filter(s).";
   return out;
 #else
-  out << "elements=[" << base::JoinString(selector.selectors, ",") << "]";
-  if (!selector.inner_text_pattern.empty()) {
-    out << " innerText =~ /";
-    out << selector.inner_text_pattern;
-    out << "/" << (selector.inner_text_pattern_case_sensitive ? "" : "i");
+  out << "[";
+  bool first = true;
+  for (const SelectorProto::Filter& filter : selector.proto.filters()) {
+    if (first) {
+      first = false;
+    } else {
+      out << " ";
+    }
+    out << filter;
   }
-  if (!selector.value_pattern.empty()) {
-    out << " value =~ /";
-    out << selector.value_pattern;
-    out << "/" << (selector.value_pattern_case_sensitive ? "" : "i");
-  }
-  if (selector.must_be_visible) {
-    out << " must_be_visible";
-  }
-  if (selector.pseudo_type != PseudoType::UNDEFINED) {
-    out << "::" << selector.pseudo_type;
-  }
+  out << "]";
   return out;
 #endif  // NDEBUG
 }
diff --git a/components/autofill_assistant/browser/selector.h b/components/autofill_assistant/browser/selector.h
index b2f920b..2e9fc11 100644
--- a/components/autofill_assistant/browser/selector.h
+++ b/components/autofill_assistant/browser/selector.h
@@ -18,6 +18,10 @@
 
 // Convenience functions for creating SelectorProtos.
 SelectorProto ToSelectorProto(const std::string& s);
+SelectorProto ToSelectorProto(const std::vector<std::string>& s);
+
+// Returns the CSS name of a pseudo-type, without "::" prefix.
+std::string PseudoTypeName(PseudoType pseudoType);
 
 // Convenience wrapper around a SelectorProto that makes it simpler to work with
 // selectors.
@@ -25,43 +29,14 @@
 // Selectors are comparables, can be used as std::map key or std::set elements
 // and converted to string with operator<<.
 struct Selector {
-  // A sequence of CSS selectors. Any non-final CSS selector is expected to
-  // arrive at a frame or an iframe, i.e. an element that contains another
-  // document.
-  std::vector<std::string> selectors;
-
-  // If true, only match visible elements. Visible elements are elements that
-  // have a box model. The box model is not checked at all, so an element with a
-  // zero size bounding box is considered visible.
-  bool must_be_visible = false;
-
-  // If non-empty, this must be a regular expression that matches the inner text
-  // of the element(s) matching selectors.
-  std::string inner_text_pattern;
-
-  // If trie, the |inner_text_pattern| will be checked case sensitively.
-  bool inner_text_pattern_case_sensitive = false;
-
-  // If non-empty, this must be a regular expression that matches the value
-  // of the element(s) matching selectors.
-  std::string value_pattern;
-
-  // If true, the |value_pattern| will be checked case sensitively.
-  bool value_pattern_case_sensitive = false;
-
-  // An optional pseudo type. This pseudo type is associated to the final
-  // element matched by |selectors|, which means that we currently don't handle
-  // matching an element inside a pseudo element.
-  PseudoType pseudo_type = PseudoType::UNDEFINED;
+  SelectorProto proto;
 
   Selector();
   ~Selector();
 
   explicit Selector(const SelectorProto& proto);
-  explicit Selector(const std::vector<std::string>& s);
-  Selector(const std::vector<std::string>& s, PseudoType p);
-
-  SelectorProto ToProto() const;
+  explicit Selector(const std::vector<std::string>& s)
+      : Selector(ToSelectorProto(s)) {}
 
   Selector(Selector&& other);
   Selector(const Selector& other);
@@ -72,16 +47,13 @@
   bool operator==(const Selector& other) const;
 
   // Convenience function to update the visible field in a fluent style.
-  Selector& MustBeVisible() {
-    must_be_visible = true;
-    return *this;
-  }
+  Selector& MustBeVisible();
 
   // The output operator. The actual selectors are only available in debug
   // builds.
   friend std::ostream& operator<<(std::ostream& out, const Selector& selector);
 
-  // Checks whether this selector is empty.
+  // Checks whether this selector is empty or invalid.
   bool empty() const;
 
   // Convenience function to set inner_text_pattern in a fluent style.
@@ -92,21 +64,27 @@
   // Convenience function  to set inner_text_pattern matching with case
   // sensitivity.
   Selector& MatchingInnerText(const std::string& pattern, bool case_sensitive) {
-    inner_text_pattern = pattern;
-    inner_text_pattern_case_sensitive = case_sensitive;
+    auto* text_filter = proto.add_filters()->mutable_inner_text();
+    text_filter->set_re2(pattern);
+    text_filter->set_case_sensitive(case_sensitive);
     return *this;
   }
 
   // Convenience function to set inner_text_pattern in a fluent style.
   Selector& MatchingValue(const std::string& pattern) {
-    value_pattern = pattern;
-    return *this;
+    return MatchingValue(pattern, false);
   }
 
   // Convenience function to set value_pattern matchinng with case sensitivity.
   Selector& MatchingValue(const std::string& pattern, bool case_sensitive) {
-    value_pattern = pattern;
-    value_pattern_case_sensitive = case_sensitive;
+    auto* text_filter = proto.add_filters()->mutable_value();
+    text_filter->set_re2(pattern);
+    text_filter->set_case_sensitive(case_sensitive);
+    return *this;
+  }
+
+  Selector& SetPseudoType(PseudoType pseudo_type) {
+    proto.add_filters()->set_pseudo_type(pseudo_type);
     return *this;
   }
 
diff --git a/components/autofill_assistant/browser/selector_unittest.cc b/components/autofill_assistant/browser/selector_unittest.cc
index b41054f..b9ffc38 100644
--- a/components/autofill_assistant/browser/selector_unittest.cc
+++ b/components/autofill_assistant/browser/selector_unittest.cc
@@ -11,66 +11,54 @@
 namespace autofill_assistant {
 namespace {
 
-TEST(SelectorTest, FromProto) {
-  SelectorProto proto;
-  proto.add_selectors("a");
-  proto.add_selectors("b");
-  proto.set_inner_text_pattern("c");
-  proto.set_inner_text_pattern_case_sensitive(true);
-  proto.set_value_pattern("d");
-  proto.set_value_pattern_case_sensitive(true);
-  proto.set_visibility_requirement(MUST_BE_VISIBLE);
-  proto.set_pseudo_type(PseudoType::BEFORE);
-
-  Selector selector(proto);
-  EXPECT_THAT(selector.selectors, testing::ElementsAre("a", "b"));
-  EXPECT_TRUE(selector.must_be_visible);
-  EXPECT_EQ("c", selector.inner_text_pattern);
-  EXPECT_TRUE(selector.inner_text_pattern_case_sensitive);
-  EXPECT_EQ("d", selector.value_pattern);
-  EXPECT_TRUE(selector.value_pattern_case_sensitive);
-  EXPECT_EQ(PseudoType::BEFORE, selector.pseudo_type);
+TEST(SelectorTest, Constructor_Simple) {
+  Selector selector({"#test"});
+  ASSERT_EQ(1, selector.proto.filters().size());
+  EXPECT_EQ("#test", selector.proto.filters(0).css_selector());
 }
 
-TEST(SelectorTest, ToProto) {
-  Selector selector;
-  selector.selectors.emplace_back("a");
-  selector.selectors.emplace_back("b");
-  selector.inner_text_pattern = "c";
-  selector.inner_text_pattern_case_sensitive = true;
-  selector.value_pattern = "d";
-  selector.value_pattern_case_sensitive = true;
-  selector.must_be_visible = true;
-  selector.pseudo_type = PseudoType::BEFORE;
+TEST(SelectorTest, Constructor_WithIframe) {
+  Selector selector({"#frame", "#test"});
+  ASSERT_EQ(4, selector.proto.filters().size());
+  EXPECT_EQ("#frame", selector.proto.filters(0).css_selector());
+  EXPECT_EQ(selector.proto.filters(1).filter_case(),
+            SelectorProto::Filter::kPickOne);
+  EXPECT_EQ(selector.proto.filters(2).filter_case(),
+            SelectorProto::Filter::kEnterFrame);
+  EXPECT_EQ("#test", selector.proto.filters(3).css_selector());
+}
 
-  SelectorProto proto = selector.ToProto();
-  EXPECT_THAT(proto.selectors(), testing::ElementsAre("a", "b"));
-  EXPECT_EQ("c", proto.inner_text_pattern());
-  EXPECT_TRUE(proto.inner_text_pattern_case_sensitive());
-  EXPECT_EQ("d", proto.value_pattern());
-  EXPECT_TRUE(proto.value_pattern_case_sensitive());
-  EXPECT_EQ(MUST_BE_VISIBLE, proto.visibility_requirement());
-  EXPECT_EQ(PseudoType::BEFORE, proto.pseudo_type());
+TEST(SelectorTest, FromProto) {
+  SelectorProto proto;
+  proto.add_filters()->set_css_selector("#test");
+
+  EXPECT_EQ(Selector({"#test"}), Selector(proto));
 }
 
 TEST(SelectorTest, Comparison) {
   EXPECT_FALSE(Selector({"a"}) == Selector({"b"}));
   EXPECT_LT(Selector({"a"}), Selector({"b"}));
   EXPECT_TRUE(Selector({"a"}) == Selector({"a"}));
+}
 
-  EXPECT_FALSE(Selector({"a"}, PseudoType::BEFORE) ==
-               Selector({"a"}, PseudoType::AFTER));
-  EXPECT_LT(Selector({"a"}, PseudoType::BEFORE),
-            Selector({"a"}, PseudoType::AFTER));
-  EXPECT_LT(Selector({"a"}, PseudoType::BEFORE), Selector({"b"}));
-  EXPECT_TRUE(Selector({"a"}, PseudoType::BEFORE) ==
-              Selector({"a"}, PseudoType::BEFORE));
+TEST(SelectorTest, Comparison_PseudoType) {
+  EXPECT_FALSE(Selector({"a"}).SetPseudoType(PseudoType::BEFORE) ==
+               Selector({"a"}).SetPseudoType(PseudoType::AFTER));
+  EXPECT_LT(Selector({"a"}).SetPseudoType(PseudoType::BEFORE),
+            Selector({"a"}).SetPseudoType(PseudoType::AFTER));
+  EXPECT_LT(Selector({"b"}), Selector({"a"}).SetPseudoType(PseudoType::BEFORE));
+  EXPECT_TRUE(Selector({"a"}).SetPseudoType(PseudoType::BEFORE) ==
+              Selector({"a"}).SetPseudoType(PseudoType::BEFORE));
+}
 
+TEST(SelectorTest, Comparison_Visibility) {
   EXPECT_FALSE(Selector({"a"}) == Selector({"a"}).MustBeVisible());
   EXPECT_LT(Selector({"a"}), Selector({"a"}).MustBeVisible());
   EXPECT_TRUE(Selector({"a"}).MustBeVisible() ==
               Selector({"a"}).MustBeVisible());
+}
 
+TEST(SelectorTest, Comparison_InnerText) {
   EXPECT_FALSE(Selector({"a"}).MatchingInnerText("a") ==
                Selector({"a"}).MatchingInnerText("b"));
   EXPECT_LT(Selector({"a"}).MatchingInnerText("a"),
@@ -84,7 +72,9 @@
             Selector({"a"}).MatchingInnerText("a", true));
   EXPECT_TRUE(Selector({"a"}).MatchingInnerText("a", true) ==
               Selector({"a"}).MatchingInnerText("a", true));
+}
 
+TEST(SelectorTest, Comparison_Value) {
   EXPECT_FALSE(Selector({"a"}).MatchingValue("a") ==
                Selector({"a"}).MatchingValue("b"));
   EXPECT_LT(Selector({"a"}).MatchingValue("a"),
@@ -100,5 +90,46 @@
               Selector({"a"}).MatchingValue("a", true));
 }
 
+TEST(SelectorTest, Comparison_Frames) {
+  Selector ab({"a", "b"});
+  EXPECT_EQ(ab, ab);
+
+  Selector cb({"c", "b"});
+  EXPECT_FALSE(ab == cb);
+  EXPECT_TRUE(ab < cb);
+  EXPECT_FALSE(cb < ab);
+
+  Selector b({"b"});
+  EXPECT_FALSE(ab == b);
+  EXPECT_TRUE(b < ab);
+  EXPECT_FALSE(ab < b);
+}
+
+TEST(SelectorTest, Comparison_MultipleFilters) {
+  Selector abcdef;
+  abcdef.proto.add_filters()->set_css_selector("abc");
+  abcdef.proto.add_filters()->set_css_selector("def");
+
+  Selector abcdef2;
+  abcdef2.proto.add_filters()->set_css_selector("abc");
+  abcdef2.proto.add_filters()->set_css_selector("def");
+  EXPECT_EQ(abcdef, abcdef2);
+  EXPECT_FALSE(abcdef < abcdef2);
+  EXPECT_FALSE(abcdef2 < abcdef);
+
+  Selector defabc;
+  defabc.proto.add_filters()->set_css_selector("def");
+  defabc.proto.add_filters()->set_css_selector("abc");
+  EXPECT_FALSE(abcdef == defabc);
+  EXPECT_TRUE(abcdef < defabc);
+  EXPECT_FALSE(defabc < abcdef);
+
+  Selector abc;
+  abc.proto.add_filters()->set_css_selector("abc");
+  EXPECT_FALSE(abcdef == abc);
+  EXPECT_TRUE(abc < abcdef);
+  EXPECT_FALSE(abcdef < abc);
+}
+
 }  // namespace
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index 2cca786..7c8f26c3 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -694,61 +694,100 @@
   INPUT_LIST_BUTTON = 15;
 }
 
-// A reference to an unique element on the page, possibly nested in frames.
+// A reference to one or more elements on the page, possibly nested in frames.
 message SelectorProto {
-  // A sequence of CSS selectors. Any non-final CSS selector is expected to
-  // arrive at a frame or an iframe, i.e. an element that contains another
-  // document.
-  // APIs are free to reject element references that do not refer to unique
-  // elements (i.e. resolve to more than one element on the page).
-  repeated string selectors = 2;
+  // Filters for the element on the page. Filter are applied sequentially, using
+  // the output of the previous filter as input. The root of these filters is
+  // the main frame's document.
+  repeated Filter filters = 9;
 
-  // If non-empty, only take into accounts the elements matched by selector
-  // whose inner text matches the given JavaScript regex. This does a search,
-  // not a full match. Add ^ and $ as necessary.
-  //
-  // This is used to filter the elements matching the last selector, before
-  // trying to get the pseudo_type, if any was set.
-  optional string inner_text_pattern = 4;
+  // A filter that starts with one or more elements and returns one on more
+  // elements. Filters are meant to be applied sequentially.
+  message Filter {
+    oneof filter {
+      // Enter the document of an iframe or shadow root. The next filters apply
+      // to the document inside of the iframe(s) or on the shadow element.
+      //
+      // Fails if there are more than one match.
+      EmptyFilter enter_frame = 1;
 
-  // If true, the |inner_text_pattern| will be checked case sensitively.
-  // Default is case insensitive.
-  optional bool inner_text_pattern_case_sensitive = 7;
+      // Evaluate the given CSS selector on all start elements and use
+      // the result as end elements.
+      string css_selector = 2;
 
-  // If non-empty, only take into accounts the elements matched by selector
-  // whose value matches the given JavaScript regex. This does a search,
-  // not a full match. Add ^ and $ as necessary.
-  //
-  // This is used to filter the elements matching the last selector, before
-  // trying to get the pseudo_type, if any was set.
-  optional string value_pattern = 6;
+      // Check the inner text of all start elements, using the Javascript
+      // innerText property. Keep only the element whose innerText match the
+      // given regular expression.
+      TextFilter inner_text = 3;
 
-  // If true, the |value_pattern| will be checked case sensitively. Default is
-  // case insensitive.
-  optional bool value_pattern_case_sensitive = 8;
+      // Check the value of all start elements, using the Javascript value
+      // property. Keep only the element whose value property match the given
+      // regular expression.
+      TextFilter value = 4;
 
-  // Specifies whether the matched element(s) must be visible.
-  //
-  // Visibility applies to the element matched in selectors; the pseudo type is
-  // checked afterwards.
-  optional VisibilityRequirement visibility_requirement = 5;
+      // Select the pseudo-element of the given type associated with the current
+      // elements.
+      PseudoType pseudo_type = 5;
 
-  // An optional pseudo type. This pseudo type is associated to the final
-  // element matched, which means that we currently don't handle matching an
-  // element inside a pseudo element.
-  optional PseudoType pseudo_type = 3;
-}
+      // Only keep elements that have a box model, even if it is empty.
+      //
+      // This is the equivalent of the old MUST_BE_VISIBLE flag. It's been
+      // renamed as having a bounding box is not enough to imply visibility.
+      EmptyFilter bounding_box = 6;
 
-enum VisibilityRequirement {
-  UNSPECIFIED_VISIBILITY = 0;
+      // Pick just one match and continue. Ignore all other matches.
+      //
+      // For backward-compatibility with older element references, pick_one can
+      // be put before enter_frame.
+      EmptyFilter pick_one = 7;
 
-  // Element must be visible. Visible elements are elements that have a box
-  // model. The box model is not checked at all, so an element with a zero size
-  // bounding box is considered visible.
-  MUST_BE_VISIBLE = 1;
+      // Only keep elements that have a pseudo-element with the given content.
+      //
+      // This only works with BEFORE and AFTER.
+      //
+      // Note that this just filters out elements. It doesn't select the
+      // pseudo-element; use pseudo_type for that.
+      PseudoElementContent pseudo_element_content = 8;
 
-  // It's enough for the element to exist in the DOM tree for it to match.
-  MUST_EXIST = 2;
+      // Go from label to the labelled control. Only works starting with current
+      // elements that are LABEL.
+      //
+      // For example if we have:
+      //  <label for="someid">First Name</label>...<input id="someid" ...>
+      // then labelled, goes from the label to the form element.
+      //
+      // So, the form element can be accessed as "label~=/FirstName/ labelled".
+      // This is especially useful in situations where someid can change.
+      //
+      // The same selector also works in the case where the element is inside of
+      // the label, so we don't need to worry which implementation is used when
+      // building the selector:
+      //   <label>First Name <input ...></label>
+      EmptyFilter labelled = 9;
+    }
+  }
+
+  // A way of filtering elements by their text.
+  message TextFilter {
+    // Javascript RE2 regular expression to apply to the text. This is evaluated
+    // with Regexp.test, so it's a "find" and will be satisfied whenever the
+    // text contains at least one substring that matches the given regular
+    // expression.
+    optional string re2 = 1;
+
+    // If true, the regular expression is case-sensitive.
+    optional bool case_sensitive = 2;
+  }
+
+  // A way of filtering elements by their pseudo-element content.
+  message PseudoElementContent {
+    optional PseudoType pseudo_type = 1;
+    optional TextFilter content = 2;
+  }
+
+  message EmptyFilter {}
+
+  reserved 1 to 8;
 }
 
 // Contain all arguments to perform a click.
diff --git a/components/autofill_assistant/browser/web/element_finder.cc b/components/autofill_assistant/browser/web/element_finder.cc
index ba2bf36..a57f597 100644
--- a/components/autofill_assistant/browser/web/element_finder.cc
+++ b/components/autofill_assistant/browser/web/element_finder.cc
@@ -14,57 +14,10 @@
 
 namespace {
 // Javascript code to get document root element.
-const char* const kGetDocumentElement =
-    R"(
-    (function() {
-      return document.documentElement;
-    }())
-    )";
+const char kGetDocumentElement[] =
+    "(function() { return document.documentElement; }())";
 
-// Javascript code to query an elements for a selector, either the first
-// (non-strict) or a single (strict) element.
-//
-// Returns undefined if no elements are found, TOO_MANY_ELEMENTS (18) if too
-// many elements were found and strict mode is enabled.
-const char* const kQuerySelector =
-    R"(function (selector, strictMode) {
-      var found = this.querySelectorAll(selector);
-      if(found.length == 0) return undefined;
-      if(found.length > 1 && strictMode) return 18;
-      return found[0];
-    })";
-
-// Javascript code to query a visible elements for a selector, either the first
-// (non-strict) or a single (strict) visible element.q
-//
-// Returns undefined if no elements are found, TOO_MANY_ELEMENTS (18) if too
-// many elements were found and strict mode is enabled.
-const char* const kQuerySelectorWithConditions =
-    R"(function (selector, strict, visible, inner_text_str,
-            inner_text_case_sensitive, value_str, value_case_sensitive) {
-        var found = this.querySelectorAll(selector);
-        var found_index = -1;
-        var inner_text_re = inner_text_str ?
-                RegExp(inner_text_str, inner_text_case_sensitive ? "" : "i") :
-                undefined;
-        var value_re = value_str ?
-                RegExp(value_str, value_case_sensitive ? "" : "i") :
-                undefined;
-        var match = function(e) {
-          if (visible && e.getClientRects().length == 0) return false;
-          if (inner_text_re && !inner_text_re.test(e.innerText)) return false;
-          if (value_re && !value_re.test(e.value)) return false;
-          return true;
-        };
-        for (let i = 0; i < found.length; i++) {
-          if (match(found[i])) {
-            if (found_index != -1) return 18;
-            found_index = i;
-            if (!strict) break;
-          }
-        }
-        return found_index == -1 ? undefined : found[found_index];
-    })";
+const char kGetArrayElement[] = "function(index) { return this[index]; }";
 
 bool ConvertPseudoType(const PseudoType pseudo_type,
                        dom::PseudoType* pseudo_type_output) {
@@ -121,11 +74,153 @@
 }
 }  // namespace
 
+ElementFinder::JsFilterBuilder::JsFilterBuilder() = default;
+ElementFinder::JsFilterBuilder::~JsFilterBuilder() = default;
+
+std::vector<std::unique_ptr<runtime::CallArgument>>
+ElementFinder::JsFilterBuilder::BuildArgumentList() const {
+  auto str_array_arg = std::make_unique<base::Value>(base::Value::Type::LIST);
+  for (const std::string& str : arguments_) {
+    str_array_arg->Append(str);
+  }
+  std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
+  arguments.emplace_back(runtime::CallArgument::Builder()
+                             .SetValue(std::move(str_array_arg))
+                             .Build());
+  return arguments;
+}
+
+// clang-format off
+std::string ElementFinder::JsFilterBuilder::BuildFunction() const {
+  return base::StrCat({
+    R"(
+    function(args) {
+      var elements = [this];
+    )",
+    base::JoinString(lines_, "\n"),
+    R"(
+      if (elements.length == 0) return null;
+      if (elements.length == 1) { return elements[0] }
+      return elements;
+    })"
+  });
+}
+// clang-format on
+
+bool ElementFinder::JsFilterBuilder::AddFilter(
+    const SelectorProto::Filter& filter) {
+  switch (filter.filter_case()) {
+    case SelectorProto::Filter::kCssSelector:
+      // clang-format off
+      AddLine({
+        "elements = elements.flatMap((e) => Array.from(e.querySelectorAll(",
+        AddArgument(filter.css_selector()),
+        ")));"
+      });
+
+      // Elements are temporarily put into a set to get rid of duplicates, which
+      // are likely when using inner text before CSS selector filters. We must
+      // not return duplicates as they cause incorrect TOO_MANY_ELEMENTS errors.
+      AddLine(R"(if (elements.length > 1) {
+        elements = Array.from(new Set(elements));
+      })");
+      // clang-format on
+      return true;
+
+    case SelectorProto::Filter::kInnerText:
+      AddRegexpFilter(filter.inner_text(), "innerText");
+      return true;
+
+    case SelectorProto::Filter::kValue:
+      AddRegexpFilter(filter.value(), "value");
+      return true;
+
+    case SelectorProto::Filter::kBoundingBox:
+      AddLine(
+          "elements = elements.filter((e) => e.getClientRects().length > 0);");
+      return true;
+
+    case SelectorProto::Filter::kPseudoElementContent: {
+      // When a content is set, window.getComputedStyle().content contains a
+      // double-quoted string with the content, unquoted here by JSON.parse().
+      std::string re_var =
+          AddRegexpInstance(filter.pseudo_element_content().content());
+      std::string pseudo_type =
+          PseudoTypeName(filter.pseudo_element_content().pseudo_type());
+
+      AddLine("elements = elements.filter((e) => {");
+      AddLine({"  var s = window.getComputedStyle(e, '", pseudo_type, "');"});
+      AddLine("  if (!s || !s.content || !s.content.startsWith('\"')) {");
+      AddLine("    return false;");
+      AddLine("  }");
+      AddLine({"  return ", re_var, ".test(JSON.parse(s.content));"});
+      AddLine("});");
+      return true;
+    }
+
+    case SelectorProto::Filter::kLabelled:
+      AddLine(R"(elements = elements.flatMap((e) => {
+  if (e.tagName != 'LABEL') return [];
+  var element = null;
+  var id = e.getAttribute('for');
+  if (id) {
+    element = document.getElementById(id)
+  }
+  if (!element) {
+    element = e.querySelector(
+      'button,input,keygen,meter,output,progress,select,textarea');
+  }
+  if (element) return [element];
+  return [];
+});
+)");
+      // The selector above for the case where there's no "for" corresponds to
+      // the list of labelable elements listed on "W3C's HTML5: Edition for Web
+      // Authors":
+      // https://www.w3.org/TR/2011/WD-html5-author-20110809/forms.html#category-label
+      return true;
+
+    case SelectorProto::Filter::kEnterFrame:
+    case SelectorProto::Filter::kPseudoType:
+    case SelectorProto::Filter::kPickOne:
+    case SelectorProto::Filter::FILTER_NOT_SET:
+      return false;
+  }
+}
+
+std::string ElementFinder::JsFilterBuilder::AddRegexpInstance(
+    const SelectorProto::TextFilter& filter) {
+  std::string re_flags = filter.case_sensitive() ? "" : "i";
+  std::string re_var = DeclareVariable();
+  AddLine({"var ", re_var, " = RegExp(", AddArgument(filter.re2()), ", '",
+           re_flags, "');"});
+  return re_var;
+}
+
+void ElementFinder::JsFilterBuilder::AddRegexpFilter(
+    const SelectorProto::TextFilter& filter,
+    const std::string& property) {
+  std::string re_var = AddRegexpInstance(filter);
+  AddLine({"elements = elements.filter((e) => ", re_var, ".test(e.", property,
+           "));"});
+}
+
+std::string ElementFinder::JsFilterBuilder::DeclareVariable() {
+  return base::StrCat({"v", base::NumberToString(variable_counter_++)});
+}
+
+std::string ElementFinder::JsFilterBuilder::AddArgument(
+    const std::string& value) {
+  int index = arguments_.size();
+  arguments_.emplace_back(value);
+  return base::StrCat({"args[", base::NumberToString(index), "]"});
+}
+
 ElementFinder::Result::Result() = default;
 
 ElementFinder::Result::~Result() = default;
 
-ElementFinder::Result::Result(const Result& to_copy) = default;
+ElementFinder::Result::Result(const Result&) = default;
 
 ElementFinder::ElementFinder(content::WebContents* web_contents,
                              DevtoolsClient* devtools_client,
@@ -134,8 +229,7 @@
     : web_contents_(web_contents),
       devtools_client_(devtools_client),
       selector_(selector),
-      strict_(strict),
-      element_result_(std::make_unique<Result>()) {}
+      strict_(strict) {}
 
 ElementFinder::~ElementFinder() = default;
 
@@ -147,21 +241,190 @@
     return;
   }
 
-  element_result_->container_frame_host = web_contents_->GetMainFrame();
-  devtools_client_->GetRuntime()->Evaluate(
-      std::string(kGetDocumentElement), /* node_frame_id= */ std::string(),
-      base::BindOnce(&ElementFinder::OnGetDocumentElement,
-                     weak_ptr_factory_.GetWeakPtr(), 0));
+  current_frame_ = web_contents_->GetMainFrame();
+  GetDocumentElement();
 }
 
 void ElementFinder::SendResult(const ClientStatus& status) {
-  DCHECK(callback_);
-  DCHECK(element_result_);
-  std::move(callback_).Run(status, std::move(element_result_));
+  if (!callback_)
+    return;
+
+  std::move(callback_).Run(status, std::make_unique<Result>());
+}
+
+void ElementFinder::SendSuccessResult(const std::string& object_id) {
+  if (!callback_)
+    return;
+
+  // Fill in result and return
+  std::unique_ptr<Result> result =
+      std::make_unique<Result>(BuildResult(object_id));
+  result->frame_stack = frame_stack_;
+  std::move(callback_).Run(OkClientStatus(), std::move(result));
+}
+
+ElementFinder::Result ElementFinder::BuildResult(const std::string& object_id) {
+  Result result;
+  result.container_frame_host = current_frame_;
+  result.object_id = object_id;
+  result.node_frame_id = current_frame_id_;
+  return result;
+}
+
+void ElementFinder::ExecuteNextTask() {
+  const auto& filters = selector_.proto.filters();
+
+  if (next_filter_index_ >= filters.size()) {
+    std::string object_id;
+    if ((strict_ && !ConsumeOneMatchOrFail(object_id)) ||
+        (!strict_ && !ConsumeAnyMatchOrFail(object_id))) {
+      return;
+    }
+    SendSuccessResult(object_id);
+    return;
+  }
+
+  const auto& filter = filters.Get(next_filter_index_);
+  switch (filter.filter_case()) {
+    case SelectorProto::Filter::kEnterFrame: {
+      std::string object_id;
+      if (!ConsumeOneMatchOrFail(object_id))
+        return;
+
+      // The above fails if there is more than one frame. To preserve
+      // backward-compatibility with the previous, lax behavior, callers must
+      // add pick_one before enter_frame. TODO(b/155264465): allow searching in
+      // more than one frame.
+      next_filter_index_++;
+      EnterFrame(object_id);
+      return;
+    }
+
+    case SelectorProto::Filter::kPseudoType: {
+      std::vector<std::string> matches;
+      if (!ConsumeAllMatchesOrFail(matches))
+        return;
+
+      next_filter_index_++;
+      matching_pseudo_elements_ = true;
+      ResolvePseudoElement(filter.pseudo_type(), matches);
+      return;
+    }
+
+    case SelectorProto::Filter::kPickOne: {
+      std::string object_id;
+      if (!ConsumeAnyMatchOrFail(object_id))
+        return;
+
+      next_filter_index_++;
+      current_matches_ = {object_id};
+      ExecuteNextTask();
+      return;
+    }
+
+    case SelectorProto::Filter::kCssSelector:
+    case SelectorProto::Filter::kInnerText:
+    case SelectorProto::Filter::kValue:
+    case SelectorProto::Filter::kBoundingBox:
+    case SelectorProto::Filter::kPseudoElementContent:
+    case SelectorProto::Filter::kLabelled: {
+      std::vector<std::string> matches;
+      if (!ConsumeAllMatchesOrFail(matches))
+        return;
+
+      JsFilterBuilder js_filter;
+      for (int i = next_filter_index_; i < filters.size(); i++) {
+        if (!js_filter.AddFilter(filters.Get(i))) {
+          break;
+        }
+        next_filter_index_++;
+      }
+      ApplyJsFilters(js_filter, matches);
+      return;
+    }
+
+    case SelectorProto::Filter::FILTER_NOT_SET:
+      VLOG(1) << __func__ << " Unset or unknown filter in " << selector_;
+      SendResult(ClientStatus(INVALID_SELECTOR));
+      return;
+  }
+}
+
+bool ElementFinder::ConsumeOneMatchOrFail(std::string& object_id_out) {
+  // This logic relies on JsFilterBuilder::BuildFunction guaranteeing that
+  // arrays contain at least 2 elements to avoid having to fetch all matching
+  // elements in the common case where we just want to know whether there is at
+  // least one match.
+
+  if (!current_match_arrays_.empty()) {
+    VLOG(1) << __func__ << " Got " << current_match_arrays_.size()
+            << " arrays of 2 or more matches for " << selector_
+            << ", when only 1 match was expected.";
+    SendResult(ClientStatus(TOO_MANY_ELEMENTS));
+    return false;
+  }
+  if (current_matches_.size() > 1) {
+    VLOG(1) << __func__ << " Got " << current_matches_.size() << " matches for "
+            << selector_ << ", when only 1 was expected.";
+    SendResult(ClientStatus(TOO_MANY_ELEMENTS));
+    return false;
+  }
+  if (current_matches_.empty()) {
+    SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+    return false;
+  }
+
+  object_id_out = current_matches_[0];
+  current_matches_.clear();
+  return true;
+}
+
+bool ElementFinder::ConsumeAnyMatchOrFail(std::string& object_id_out) {
+  // This logic relies on ApplyJsFilters guaranteeing that arrays contain at
+  // least 2 elements to avoid having to fetch all matching elements in the
+  // common case where we just want one match.
+
+  if (current_matches_.size() > 0) {
+    object_id_out = current_matches_[0];
+    current_matches_.clear();
+    current_match_arrays_.clear();
+    return true;
+  }
+  if (!current_match_arrays_.empty()) {
+    std::string array_object_id = current_match_arrays_[0];
+    current_match_arrays_.clear();
+    ResolveMatchArrays({array_object_id}, /* max_count= */ 1);
+    return false;  // Caller should call again to check
+  }
+  SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+  return false;
+}
+
+bool ElementFinder::ConsumeAllMatchesOrFail(
+    std::vector<std::string>& matches_out) {
+  if (!current_match_arrays_.empty()) {
+    std::vector<std::string> array_object_ids =
+        std::move(current_match_arrays_);
+    ResolveMatchArrays(array_object_ids, /* max_count= */ -1);
+    return false;  // Caller should call again to check
+  }
+  if (!current_matches_.empty()) {
+    matches_out = std::move(current_matches_);
+    current_matches_.clear();
+    return true;
+  }
+  SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+  return false;
+}
+
+void ElementFinder::GetDocumentElement() {
+  devtools_client_->GetRuntime()->Evaluate(
+      std::string(kGetDocumentElement), current_frame_id_,
+      base::BindOnce(&ElementFinder::OnGetDocumentElement,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void ElementFinder::OnGetDocumentElement(
-    size_t index,
     const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::EvaluateResult> result) {
   ClientStatus status =
@@ -178,50 +441,31 @@
     return;
   }
 
-  RecursiveFindElement(object_id, index);
+  // Use the node as root for the rest of the evaluation.
+  current_matches_.emplace_back(object_id);
+
+  DecrementResponseCountAndContinue();
 }
 
-void ElementFinder::RecursiveFindElement(const std::string& object_id,
-                                         size_t index) {
-  std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
-  AddRuntimeCallArgument(selector_.selectors[index], &arguments);
-  // For finding intermediate elements, strict mode would be more appropriate,
-  // as long as the logic does not support more than one intermediate match.
-  //
-  // TODO(b/129387787): first, add logging to figure out whether it matters and
-  // decide between strict mode and full support for multiple matching
-  // intermeditate elements.
-  AddRuntimeCallArgument(strict_, &arguments);
-  std::string function;
-  if (index == (selector_.selectors.size() - 1)) {
-    if (selector_.must_be_visible || !selector_.inner_text_pattern.empty() ||
-        !selector_.value_pattern.empty()) {
-      function.assign(kQuerySelectorWithConditions);
-      AddRuntimeCallArgument(selector_.must_be_visible, &arguments);
-      AddRuntimeCallArgument(selector_.inner_text_pattern, &arguments);
-      AddRuntimeCallArgument(selector_.inner_text_pattern_case_sensitive,
-                             &arguments);
-      AddRuntimeCallArgument(selector_.value_pattern, &arguments);
-      AddRuntimeCallArgument(selector_.value_pattern_case_sensitive,
-                             &arguments);
-    }
+void ElementFinder::ApplyJsFilters(const JsFilterBuilder& builder,
+                                   const std::vector<std::string>& object_ids) {
+  DCHECK(!object_ids.empty());  // Guaranteed by ExecuteNextTask()
+  pending_response_count_ = object_ids.size();
+  std::string function = builder.BuildFunction();
+  for (const std::string& object_id : object_ids) {
+    devtools_client_->GetRuntime()->CallFunctionOn(
+        runtime::CallFunctionOnParams::Builder()
+            .SetObjectId(object_id)
+            .SetArguments(builder.BuildArgumentList())
+            .SetFunctionDeclaration(function)
+            .Build(),
+        current_frame_id_,
+        base::BindOnce(&ElementFinder::OnApplyJsFilters,
+                       weak_ptr_factory_.GetWeakPtr()));
   }
-  if (function.empty()) {
-    function.assign(kQuerySelector);
-  }
-  devtools_client_->GetRuntime()->CallFunctionOn(
-      runtime::CallFunctionOnParams::Builder()
-          .SetObjectId(object_id)
-          .SetArguments(std::move(arguments))
-          .SetFunctionDeclaration(function)
-          .Build(),
-      element_result_->node_frame_id,
-      base::BindOnce(&ElementFinder::OnQuerySelectorAll,
-                     weak_ptr_factory_.GetWeakPtr(), index));
 }
 
-void ElementFinder::OnQuerySelectorAll(
-    size_t index,
+void ElementFinder::OnApplyJsFilters(
     const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
   if (!result) {
@@ -229,63 +473,54 @@
     // available yet to query because the document hasn't been loaded. This
     // results in OnQuerySelectorAll getting a nullptr result. For this specific
     // call, it is expected.
-    VLOG(1) << __func__ << ": Context doesn't exist yet to query selector "
-            << index << " of " << selector_;
+    VLOG(1) << __func__ << ": Context doesn't exist yet to query frame "
+            << frame_stack_.size() << " of " << selector_;
     SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
     return;
   }
   ClientStatus status =
       CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
   if (!status.ok()) {
-    VLOG(1) << __func__ << ": Failed to query selector " << index << " of "
-            << selector_;
+    VLOG(1) << __func__ << ": Failed to query selector for frame "
+            << frame_stack_.size() << " of " << selector_ << ": " << status;
     SendResult(status);
     return;
   }
-  int int_result;
-  if (SafeGetIntValue(result->GetResult(), &int_result)) {
-    DCHECK(int_result == TOO_MANY_ELEMENTS);
-    SendResult(ClientStatus(TOO_MANY_ELEMENTS));
-    return;
-  }
+
+  // The result can be empty (nothing found), a an array (multiple matches
+  // found) or a single node.
   std::string object_id;
-  if (!SafeGetObjectId(result->GetResult(), &object_id)) {
-    SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+  if (SafeGetObjectId(result->GetResult(), &object_id)) {
+    if (result->GetResult()->HasSubtype() &&
+        result->GetResult()->GetSubtype() ==
+            runtime::RemoteObjectSubtype::ARRAY) {
+      current_match_arrays_.emplace_back(object_id);
+    } else {
+      current_matches_.emplace_back(object_id);
+    }
+  }
+  DecrementResponseCountAndContinue();
+}
+
+void ElementFinder::ResolvePseudoElement(
+    PseudoType proto_pseudo_type,
+    const std::vector<std::string>& object_ids) {
+  dom::PseudoType pseudo_type;
+  if (!ConvertPseudoType(proto_pseudo_type, &pseudo_type)) {
+    VLOG(1) << __func__ << ": Unsupported pseudo-type in " << selector_;
+    SendResult(ClientStatus(INVALID_ACTION));
     return;
   }
 
-  if (selector_.selectors.size() == index + 1) {
-    // The pseudo type is associated to the final element matched by
-    // |selector_|, which means that we currently don't handle matching an
-    // element inside a pseudo element.
-    if (selector_.pseudo_type == PseudoType::UNDEFINED) {
-      // Return object id of the element.
-      element_result_->object_id = object_id;
-      SendResult(OkClientStatus());
-      return;
-    }
-
-    // We are looking for a pseudo element associated with this element.
-    dom::PseudoType pseudo_type;
-    if (!ConvertPseudoType(selector_.pseudo_type, &pseudo_type)) {
-      // Return empty result.
-      SendResult(ClientStatus(INVALID_ACTION));
-      return;
-    }
-
+  DCHECK(!object_ids.empty());  // Guaranteed by ExecuteNextTask()
+  pending_response_count_ = object_ids.size();
+  for (const std::string& object_id : object_ids) {
     devtools_client_->GetDOM()->DescribeNode(
         dom::DescribeNodeParams::Builder().SetObjectId(object_id).Build(),
-        element_result_->node_frame_id,
+        current_frame_id_,
         base::BindOnce(&ElementFinder::OnDescribeNodeForPseudoElement,
                        weak_ptr_factory_.GetWeakPtr(), pseudo_type));
-    return;
   }
-
-  devtools_client_->GetDOM()->DescribeNode(
-      dom::DescribeNodeParams::Builder().SetObjectId(object_id).Build(),
-      element_result_->node_frame_id,
-      base::BindOnce(&ElementFinder::OnDescribeNode,
-                     weak_ptr_factory_.GetWeakPtr(), object_id, index));
 }
 
 void ElementFinder::OnDescribeNodeForPseudoElement(
@@ -307,30 +542,35 @@
             dom::ResolveNodeParams::Builder()
                 .SetBackendNodeId(pseudo_element->GetBackendNodeId())
                 .Build(),
-            element_result_->node_frame_id,
+            current_frame_id_,
             base::BindOnce(&ElementFinder::OnResolveNodeForPseudoElement,
                            weak_ptr_factory_.GetWeakPtr()));
         return;
       }
     }
   }
-
-  // Failed to find the pseudo element: run the callback with empty result.
-  SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+  DecrementResponseCountAndContinue();
 }
 
 void ElementFinder::OnResolveNodeForPseudoElement(
     const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<dom::ResolveNodeResult> result) {
   if (result && result->GetObject() && result->GetObject()->HasObjectId()) {
-    element_result_->object_id = result->GetObject()->GetObjectId();
+    current_matches_.emplace_back(result->GetObject()->GetObjectId());
   }
-  SendResult(OkClientStatus());
+  DecrementResponseCountAndContinue();
 }
 
-void ElementFinder::OnDescribeNode(
+void ElementFinder::EnterFrame(const std::string& object_id) {
+  devtools_client_->GetDOM()->DescribeNode(
+      dom::DescribeNodeParams::Builder().SetObjectId(object_id).Build(),
+      current_frame_id_,
+      base::BindOnce(&ElementFinder::OnDescribeNodeForFrame,
+                     weak_ptr_factory_.GetWeakPtr(), object_id));
+}
+
+void ElementFinder::OnDescribeNodeForFrame(
     const std::string& object_id,
-    size_t index,
     const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<dom::DescribeNodeResult> result) {
   if (!result || !result->GetNode()) {
@@ -345,41 +585,24 @@
   if (node->GetNodeName() == "IFRAME") {
     DCHECK(node->HasFrameId());  // Ensure all frames have an id.
 
-    element_result_->container_frame_host =
-        FindCorrespondingRenderFrameHost(node->GetFrameId());
+    frame_stack_.push_back(BuildResult(object_id));
 
-    Result result_frame;
-    result_frame.container_frame_host = element_result_->container_frame_host;
-    result_frame.object_id = object_id;
-    element_result_->frame_stack.emplace_back(result_frame);
-
-    if (!element_result_->container_frame_host) {
+    current_frame_ = FindCorrespondingRenderFrameHost(node->GetFrameId());
+    if (!current_frame_) {
       VLOG(1) << __func__ << " Failed to find corresponding owner frame.";
       SendResult(ClientStatus(FRAME_HOST_NOT_FOUND));
       return;
     }
 
     if (node->HasContentDocument()) {
-      // If the frame has a ContentDocument it's considered a local frame. We
-      // don't need to assign the frame id, since devtools can just send the
-      // commands to the main session.
-
+      // If the frame has a ContentDocument it's considered a local frame. In
+      // this case, current_frame_ doesn't change and can directly use the
+      // content document as root for the evaluation.
       backend_ids.emplace_back(node->GetContentDocument()->GetBackendNodeId());
     } else {
-      // If the frame has no ContentDocument, it's considered an
-      // OutOfProcessIFrame.
-      // See https://www.chromium.org/developers/design-documents/oop-iframes
-      // for full documentation.
-      // With the iFrame running in a different process it is necessary to pass
-      // the correct session id from devtools. We need to set the frame id,
-      // such that devtools can resolve the corresponding session id.
-      element_result_->node_frame_id = node->GetFrameId();
-
+      current_frame_id_ = node->GetFrameId();
       // Kick off another find element chain to walk down the OOP iFrame.
-      devtools_client_->GetRuntime()->Evaluate(
-          std::string(kGetDocumentElement), element_result_->node_frame_id,
-          base::BindOnce(&ElementFinder::OnGetDocumentElement,
-                         weak_ptr_factory_.GetWeakPtr(), index + 1));
+      GetDocumentElement();
       return;
     }
   }
@@ -395,17 +618,20 @@
         dom::ResolveNodeParams::Builder()
             .SetBackendNodeId(backend_ids[0])
             .Build(),
-        element_result_->node_frame_id,
+        current_frame_id_,
         base::BindOnce(&ElementFinder::OnResolveNode,
-                       weak_ptr_factory_.GetWeakPtr(), index));
+                       weak_ptr_factory_.GetWeakPtr()));
     return;
   }
 
-  RecursiveFindElement(object_id, index + 1);
+  // Element was not a frame and didn't have shadow dom. This is unexpected, but
+  // to remain backward compatible, don't complain and just continue filtering
+  // with the current element as root.
+  current_matches_.emplace_back(object_id);
+  DecrementResponseCountAndContinue();
 }
 
 void ElementFinder::OnResolveNode(
-    size_t index,
     const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<dom::ResolveNodeResult> result) {
   if (!result || !result->GetObject() || !result->GetObject()->HasObjectId()) {
@@ -414,7 +640,9 @@
     return;
   }
 
-  RecursiveFindElement(result->GetObject()->GetObjectId(), ++index);
+  // Use the node as root for the rest of the evaluation.
+  current_matches_.emplace_back(result->GetObject()->GetObjectId());
+  DecrementResponseCountAndContinue();
 }
 
 content::RenderFrameHost* ElementFinder::FindCorrespondingRenderFrameHost(
@@ -428,4 +656,79 @@
   return nullptr;
 }
 
+void ElementFinder::ResolveMatchArrays(
+    const std::vector<std::string>& array_object_ids,
+    int max_count) {
+  if (array_object_ids.empty()) {
+    // Nothing to do
+    ExecuteNextTask();
+    return;
+  }
+  pending_response_count_ = array_object_ids.size();
+  for (const std::string& array_object_id : array_object_ids) {
+    ResolveMatchArrayRecursive(array_object_id, 0, max_count);
+  }
+}
+
+void ElementFinder::ResolveMatchArrayRecursive(
+    const std::string& array_object_id,
+    int index,
+    int max_count) {
+  std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
+  AddRuntimeCallArgument(index, &arguments);
+  devtools_client_->GetRuntime()->CallFunctionOn(
+      runtime::CallFunctionOnParams::Builder()
+          .SetObjectId(array_object_id)
+          .SetArguments(std::move(arguments))
+          .SetFunctionDeclaration(std::string(kGetArrayElement))
+          .Build(),
+      current_frame_id_,
+      base::BindOnce(&ElementFinder::OnResolveMatchArray,
+                     weak_ptr_factory_.GetWeakPtr(), array_object_id, index,
+                     max_count));
+}
+
+void ElementFinder::OnResolveMatchArray(
+    const std::string& array_object_id,
+    int index,
+    int max_count,
+    const DevtoolsClient::ReplyStatus& reply_status,
+    std::unique_ptr<runtime::CallFunctionOnResult> result) {
+  ClientStatus status =
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
+  if (!status.ok()) {
+    VLOG(1) << __func__ << ": Failed to get element from array for "
+            << selector_;
+    SendResult(status);
+    return;
+  }
+  std::string object_id;
+  if (!SafeGetObjectId(result->GetResult(), &object_id)) {
+    // We've reached the end of the array
+    DecrementResponseCountAndContinue();
+    return;
+  }
+
+  current_matches_.emplace_back(object_id);
+  int next_index = index + 1;
+  if (max_count != -1 && next_index >= max_count) {
+    DecrementResponseCountAndContinue();
+    return;
+  }
+
+  // Fetch the next element.
+  ResolveMatchArrayRecursive(array_object_id, next_index, max_count);
+}
+
+void ElementFinder::DecrementResponseCountAndContinue() {
+  if (pending_response_count_ > 1) {
+    pending_response_count_--;
+    return;
+  }
+
+  pending_response_count_ = 0;
+  ExecuteNextTask();
+  return;
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/web/element_finder.h b/components/autofill_assistant/browser/web/element_finder.h
index e41ab82..62c1fe5a 100644
--- a/components/autofill_assistant/browser/web/element_finder.h
+++ b/components/autofill_assistant/browser/web/element_finder.h
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/strings/strcat.h"
 #include "components/autofill_assistant/browser/client_status.h"
 #include "components/autofill_assistant/browser/devtools/devtools/domains/types_dom.h"
 #include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
@@ -32,15 +33,17 @@
   struct Result {
     Result();
     ~Result();
-    Result(const Result& to_copy);
+    Result(const Result&);
 
     // The render frame host contains the element.
-    content::RenderFrameHost* container_frame_host;
+    content::RenderFrameHost* container_frame_host = nullptr;
 
     // The object id of the element.
     std::string object_id;
 
-    // The id of the frame the element's node is in.
+    // The frame id to use to execute devtools Javascript calls within the
+    // context of the frame. Might be empty if no frame id needs to be
+    // specified.
     std::string node_frame_id;
 
     std::vector<Result> frame_stack;
@@ -61,15 +64,117 @@
   void Start(Callback callback_);
 
  private:
+  // Helper for building JavaScript functions.
+  //
+  // TODO(b/155264465): extract this into a top-level class in its own file, so
+  // it can be tested.
+  class JsFilterBuilder {
+   public:
+    JsFilterBuilder();
+    ~JsFilterBuilder();
+
+    // Builds the argument list for the function.
+    std::vector<std::unique_ptr<runtime::CallArgument>> BuildArgumentList()
+        const;
+
+    // Return the JavaScript function.
+    std::string BuildFunction() const;
+
+    // Adds a filter, if possible.
+    bool AddFilter(const SelectorProto::Filter& filter);
+
+   private:
+    std::vector<std::string> arguments_;
+    std::vector<std::string> lines_;
+
+    // A number that's increased by each call to DeclareVariable() to make sure
+    // we generate unique variables.
+    int variable_counter_ = 0;
+
+    // Adds a regexp filter.
+    void AddRegexpFilter(const SelectorProto::TextFilter& filter,
+                         const std::string& property);
+
+    // Declares and initializes a variable containing a RegExp object that
+    // correspond to [filter] and returns the variable name.
+    std::string AddRegexpInstance(const SelectorProto::TextFilter& filter);
+
+    // Returns the name of a new unique variable.
+    std::string DeclareVariable();
+
+    // Adds an argument to the argument list and returns its JavaScript
+    // representation.
+    //
+    // This allows passing strings to the JavaScript code without having to
+    // hardcode and escape them - this helps avoid XSS issues.
+    std::string AddArgument(const std::string& value);
+
+    // Adds a line of JavaScript code to the function, between the header and
+    // footer. At that point, the variable "elements" contains the current set
+    // of matches, as an array of nodes. It should be updated to contain the new
+    // set of matches.
+    void AddLine(const std::string& line) { lines_.emplace_back(line); }
+
+    void AddLine(const std::vector<std::string>& line) {
+      lines_.emplace_back(base::StrCat(line));
+    }
+  };
+
+  // Sends a result with the given status and no data.
   void SendResult(const ClientStatus& status);
-  void OnGetDocumentElement(size_t index,
-                            const DevtoolsClient::ReplyStatus& reply_status,
+
+  // Builds a result from the current state of the finder and returns it.
+  void SendSuccessResult(const std::string& object_id);
+
+  // Report [object_id] as result in [result] and initialize the frame-related
+  // fields of [result] from the current state. Leaves the frame stack empty.
+  Result BuildResult(const std::string& object_id);
+
+  // Figures out what to do next given the current state.
+  //
+  // Most background operations in this worker end by updating the state and
+  // calling ExecuteNextTask() again either directly or through
+  // DecrementResponseCountAndContinue().
+  void ExecuteNextTask();
+
+  // Make sure there's exactly one match, set it [object_id_out] then return
+  // true.
+  //
+  // If there are too many or too few matches, this function sends an error and
+  // returns false.
+  bool ConsumeOneMatchOrFail(std::string& object_id_out);
+
+  // Make sure there's at least one match, take one and put it in
+  // [object_id_out], then return true.
+  //
+  // If there are no matches, send an error response and return false.
+  // If there are not enough matches yet, fetch them in the background and
+  // return false. This calls ExecuteNextTask() once matches have been fetched.
+  bool ConsumeAnyMatchOrFail(std::string& object_id_out);
+
+  // Make sure there's at least one match and move them all into
+  // [matches_out].
+  //
+  // If there are no matches, send an error response and return false.
+  // If there are not enough matches yet, fetch them in the background and
+  // return false. This calls ExecuteNextTask() once matches have been fetched.
+  bool ConsumeAllMatchesOrFail(std::vector<std::string>& matches_out);
+
+  // Gets a document element from the current frame and us it as root for the
+  // rest of the tasks.
+  void GetDocumentElement();
+  void OnGetDocumentElement(const DevtoolsClient::ReplyStatus& reply_status,
                             std::unique_ptr<runtime::EvaluateResult> result);
-  void RecursiveFindElement(const std::string& object_id, size_t index);
-  void OnQuerySelectorAll(
-      size_t index,
-      const DevtoolsClient::ReplyStatus& reply_status,
-      std::unique_ptr<runtime::CallFunctionOnResult> result);
+
+  // Handle Javascript filters
+  void ApplyJsFilters(const JsFilterBuilder& builder,
+                      const std::vector<std::string>& object_ids);
+  void OnApplyJsFilters(const DevtoolsClient::ReplyStatus& reply_status,
+                        std::unique_ptr<runtime::CallFunctionOnResult> result);
+
+  // Handle PSEUDO_TYPE
+  void ResolvePseudoElement(PseudoType pseudo_type,
+                            const std::vector<std::string>& object_ids);
   void OnDescribeNodeForPseudoElement(
       dom::PseudoType pseudo_type,
       const DevtoolsClient::ReplyStatus& reply_status,
@@ -77,24 +182,90 @@
   void OnResolveNodeForPseudoElement(
       const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<dom::ResolveNodeResult> result);
-  void OnDescribeNode(const std::string& object_id,
-                      size_t index,
-                      const DevtoolsClient::ReplyStatus& reply_status,
-                      std::unique_ptr<dom::DescribeNodeResult> result);
-  void OnResolveNode(size_t index,
-                     const DevtoolsClient::ReplyStatus& reply_status,
-                     std::unique_ptr<dom::ResolveNodeResult> result);
 
+  // Handle ENTER_FRAME
+  void EnterFrame(const std::string& object_id);
+  void OnDescribeNodeForFrame(const std::string& object_id,
+                              const DevtoolsClient::ReplyStatus& reply_status,
+                              std::unique_ptr<dom::DescribeNodeResult> result);
+  void OnResolveNode(const DevtoolsClient::ReplyStatus& reply_status,
+                     std::unique_ptr<dom::ResolveNodeResult> result);
   content::RenderFrameHost* FindCorrespondingRenderFrameHost(
       std::string frame_id);
 
+  // Get elements from [array_object_ids], and put the result into
+  // [element_matches_].
+  //
+  // This calls ExecuteNextTask() once all the elements of all the arrays are in
+  // [element_matches_]. If [max_count] is -1, fetch until the end of the array,
+  // otherwise fetch [max_count] elements at most in each array.
+  void ResolveMatchArrays(const std::vector<std::string>& array_object_ids,
+                          int max_count);
+
+  // ResolveMatchArrayRecursive calls itself recursively, incrementing [index],
+  // as long as there are elements. The chain of calls end with
+  // DecrementResponseCountAndContinue() as there can be more than one such
+  // chains executing at a time.
+  void ResolveMatchArrayRecursive(const std::string& array_object_ids,
+                                  int index,
+                                  int max_count);
+
+  void OnResolveMatchArray(
+      const std::string& array_object_id,
+      int index,
+      int max_count,
+      const DevtoolsClient::ReplyStatus& reply_status,
+      std::unique_ptr<runtime::CallFunctionOnResult> result);
+
+  // Tracks pending_response_count_ and call ExecuteNextTask() once the count
+  // has reached 0.
+  void DecrementResponseCountAndContinue();
+
   content::WebContents* const web_contents_;
   DevtoolsClient* const devtools_client_;
   const Selector selector_;
-
   const bool strict_;
   Callback callback_;
-  std::unique_ptr<Result> element_result_;
+
+  // The index of the next filter to process, in selector_.proto.filters.
+  int next_filter_index_ = 0;
+
+  // Pointer to the current frame
+  content::RenderFrameHost* current_frame_ = nullptr;
+
+  // The frame id to use to execute devtools Javascript calls within the
+  // context of the frame. Might be empty if no frame id needs to be
+  // specified.
+  std::string current_frame_id_;
+
+  // Object IDs of the current set matching elements. Cleared once it's used to
+  // query or filter.
+  //
+  // More matches can be found in [current_match_arrays_]. Use one of the
+  // Consume*Match() function to current matches.
+  std::vector<std::string> current_matches_;
+
+  // Object ID of arrays of at least 2 matching elements.
+  //
+  // More matches can be found in [current_matches_]. Use one of the
+  // Consume*Match() function to current matches.
+  std::vector<std::string> current_match_arrays_;
+
+  // True if current_matches are pseudo-elements.
+  bool matching_pseudo_elements_ = false;
+
+  // Number of responses still pending.
+  //
+  // Before starting several background operations in parallel, set this counter
+  // to the number of operations and make sure that
+  // DecrementResponseCountAndContinue() is called once the result of the
+  // operation has been processed and the state of ElementFinder updated.
+  // DecrementResponseCountAndContinue() will then make sure to call
+  // ExecuteNextTask() again once this counter has reached 0 to continue the
+  // work.
+  size_t pending_response_count_ = 0;
+
+  std::vector<Result> frame_stack_;
 
   base::WeakPtrFactory<ElementFinder> weak_ptr_factory_{this};
 };
diff --git a/components/autofill_assistant/browser/web/web_controller_browsertest.cc b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
index 2488461b..7a0f940b6 100644
--- a/components/autofill_assistant/browser/web/web_controller_browsertest.cc
+++ b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
@@ -129,7 +129,8 @@
                                    size_t* pending_number_of_checks_output,
                                    bool expected_result,
                                    const ClientStatus& result) {
-    EXPECT_EQ(expected_result, result.ok()) << "selector: " << selector;
+    EXPECT_EQ(expected_result, result.ok())
+        << "selector: " << selector << " status: " << result;
     *pending_number_of_checks_output -= 1;
     if (*pending_number_of_checks_output == 0) {
       std::move(done_callback).Run();
@@ -548,15 +549,16 @@
 
 IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, PseudoElementChecks) {
   // A pseudo-element
-  RunLaxElementCheck(Selector({"#terms-and-conditions"}, BEFORE), true);
+  RunLaxElementCheck(Selector({"#terms-and-conditions"}).SetPseudoType(BEFORE),
+                     true);
 
   // An invisible pseudo-element
   //
   // TODO(b/129461999): This is wrong; it should exist. Fix it.
-  RunLaxElementCheck(Selector({"#button"}, BEFORE), false);
+  RunLaxElementCheck(Selector({"#button"}).SetPseudoType(BEFORE), false);
 
   // A non-existent pseudo-element
-  RunLaxElementCheck(Selector({"#button"}, AFTER), false);
+  RunLaxElementCheck(Selector({"#button"}).SetPseudoType(AFTER), false);
 }
 
 IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ElementInFrameChecks) {
@@ -593,13 +595,16 @@
 
   // A pseudo-element
   RunLaxElementCheck(
-      Selector({"#terms-and-conditions"}, BEFORE).MustBeVisible(), true);
+      Selector({"#terms-and-conditions"}).MustBeVisible().SetPseudoType(BEFORE),
+      true);
 
   // An invisible pseudo-element
-  RunLaxElementCheck(Selector({"#button"}, BEFORE).MustBeVisible(), false);
+  RunLaxElementCheck(
+      Selector({"#button"}).MustBeVisible().SetPseudoType(BEFORE), false);
 
   // A non-existent pseudo-element
-  RunLaxElementCheck(Selector({"#button"}, AFTER).MustBeVisible(), false);
+  RunLaxElementCheck(Selector({"#button"}).MustBeVisible().SetPseudoType(AFTER),
+                     false);
 
   // An iFrame.
   RunLaxElementCheck(Selector({"#iframe"}).MustBeVisible(), true);
@@ -635,6 +640,19 @@
                         false);
 }
 
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, SearchMultipleIframes) {
+  // There are two "iframe" elements in the document so the selector would need
+  // to search in both iframes, which isn't supported.
+  SelectorProto proto;
+  proto.add_filters()->set_css_selector("iframe");
+  proto.add_filters()->mutable_enter_frame();
+  proto.add_filters()->set_css_selector("#element_in_iframe_two");
+
+  ClientStatus status;
+  FindElement(Selector(proto), &status, nullptr);
+  EXPECT_EQ(TOO_MANY_ELEMENTS, status.proto_status());
+}
+
 IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, InnerTextCondition) {
   const Selector base_selector({"#with_inner_text span"});
   Selector selector = base_selector;
@@ -684,17 +702,143 @@
   selector.MustBeVisible();
   RunLaxElementCheck(selector, true);
   RunStrictElementCheck(selector, true);
+}
 
-  // Inner text conditions are applied before looking for the pseudo-type.
-  selector = Selector({"#with_inner_text span"}, PseudoType::BEFORE);
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, PseudoTypeAndInnerText) {
+  // Inner text conditions then pseudo type vs pseudo type then inner text
+  // condition.
+  Selector selector({"#with_inner_text span"});
   selector.MatchingInnerText("world");
+  selector.SetPseudoType(PseudoType::BEFORE);
   RunLaxElementCheck(selector, true);
 
-  selector = Selector({"#with_inner_text span"}, PseudoType::BEFORE);
-  selector.MatchingInnerText("before");  // matches :before content
+  // "before" is the content of the :before, checking the text of pseudo-types
+  // doesn't work.
+  selector = Selector({"#with_inner_text span"});
+  selector.SetPseudoType(PseudoType::BEFORE);
+  selector.MatchingInnerText("before");
   RunLaxElementCheck(selector, false);
 }
 
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, MultipleBefore) {
+  Selector selector({"span"});
+  selector.SetPseudoType(PseudoType::BEFORE);
+
+  // There's more than one "span" with a before, so only a lax check can
+  // succeed.
+  RunLaxElementCheck(selector, true);
+  RunStrictElementCheck(selector, false);
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, PseudoTypeThenBoundingBox) {
+  Selector selector({"span"});
+  selector.SetPseudoType(PseudoType::BEFORE);
+  selector.proto.add_filters()->mutable_bounding_box();
+
+  RunLaxElementCheck(selector, true);
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, PseudoTypeThenPickOne) {
+  Selector selector({"span"});
+  selector.SetPseudoType(PseudoType::BEFORE);
+  selector.proto.add_filters()->mutable_pick_one();
+
+  RunStrictElementCheck(selector, true);
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, PseudoTypeThenCss) {
+  Selector selector({"span"});
+  selector.SetPseudoType(PseudoType::BEFORE);
+  selector.proto.add_filters()->set_css_selector("div");
+
+  // This makes no sense, but shouldn't return an unexpected error.
+  ClientStatus status;
+  ElementFinder::Result result;
+  FindElement(selector, &status, &result);
+  EXPECT_EQ(ELEMENT_RESOLUTION_FAILED, status.proto_status());
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, PseudoTypeThenInnerText) {
+  Selector selector({"span"});
+  selector.SetPseudoType(PseudoType::BEFORE);
+  selector.proto.add_filters()->mutable_inner_text()->set_re2("before");
+
+  // This isn't supported yet.
+  RunLaxElementCheck(selector, false);
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, PseudoTypeContent) {
+  Selector selector({"#with_inner_text span"});
+  auto* content =
+      selector.proto.add_filters()->mutable_pseudo_element_content();
+  content->set_pseudo_type(PseudoType::BEFORE);
+  content->mutable_content()->set_re2("before");
+  RunLaxElementCheck(selector, true);
+
+  content->mutable_content()->set_re2("nomatch");
+  RunLaxElementCheck(selector, false);
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, InnerTextThenCss) {
+  // There are two divs containing "Section with text", but only one has a
+  // button, which removes #button.
+  SelectorProto proto;
+  proto.add_filters()->set_css_selector("div");
+  proto.add_filters()->mutable_inner_text()->set_re2("Section with text");
+  proto.add_filters()->set_css_selector("button");
+
+  ClickOrTapElement(Selector(proto), ClickType::CLICK);
+  WaitForElementRemove(Selector({"#button"}));
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, FindFormInputByLabel) {
+  // #option1_label refers to the labelled control by id.
+  Selector option1;
+  option1.proto.add_filters()->set_css_selector("#option1_label");
+  option1.proto.add_filters()->mutable_labelled();
+
+  const std::string option1_checked = R"(
+    document.querySelector("#option1").checked;
+  )";
+  EXPECT_FALSE(content::EvalJs(shell(), option1_checked).ExtractBool());
+  ClickOrTapElement(option1, ClickType::CLICK);
+  EXPECT_TRUE(content::EvalJs(shell(), option1_checked).ExtractBool());
+
+  // #option2 contains the labelled control.
+  Selector option2;
+  option2.proto.add_filters()->set_css_selector("#option2_label");
+  option2.proto.add_filters()->mutable_labelled();
+
+  const std::string option2_checked = R"(
+    document.querySelector("#option2").checked;
+  )";
+  EXPECT_FALSE(content::EvalJs(shell(), option2_checked).ExtractBool());
+  ClickOrTapElement(option2, ClickType::CLICK);
+  EXPECT_TRUE(content::EvalJs(shell(), option2_checked).ExtractBool());
+
+  // #button is not a label.
+  Selector not_a_label;
+  not_a_label.proto.add_filters()->set_css_selector("#button");
+  not_a_label.proto.add_filters()->mutable_labelled();
+
+  // #bad_label1 and #bad_label2 are labels that don't reference a valid
+  // element. They must not cause JavaScript errors.
+  Selector bad_label1;
+  bad_label1.proto.add_filters()->set_css_selector("#bad_label1");
+  bad_label1.proto.add_filters()->mutable_labelled();
+
+  ClientStatus status;
+  FindElement(bad_label1, &status, nullptr);
+  EXPECT_EQ(ELEMENT_RESOLUTION_FAILED, status.proto_status());
+
+  Selector bad_label2;
+  bad_label2.proto.add_filters()->set_css_selector("#bad_label2");
+  bad_label2.proto.add_filters()->mutable_labelled();
+
+  FindElement(bad_label2, &status, nullptr);
+  EXPECT_EQ(ELEMENT_RESOLUTION_FAILED, status.proto_status());
+}
+
 IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ValueCondition) {
   // One match
   RunLaxElementCheck(Selector({"#input1"}).MatchingValue("helloworld1"), true);
@@ -838,13 +982,15 @@
   WaitForElementRemove(area_one);
 }
 
-IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, TapElementMovingOutOfView) {
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
+                       DISABLED_TapElementMovingOutOfView) {
   Selector selector({"#touch_area_three"});
   ClickOrTapElement(selector, ClickType::TAP);
   WaitForElementRemove(selector);
 }
 
-IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, TapElementAfterPageIsIdle) {
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
+                       DISABLED_TapElementAfterPageIsIdle) {
   // Set a very long timeout to make sure either the page is idle or the test
   // timeout.
   WaitTillPageIsIdle(base::TimeDelta::FromHours(1));
@@ -864,7 +1010,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
-                       TapRandomMovingElementRepeatedly) {
+                       DISABLED_TapRandomMovingElementRepeatedly) {
   Selector button_selector({"#random_moving_button"});
   int num_clicks = 100;
   for (int i = 0; i < num_clicks; ++i) {
@@ -915,8 +1061,8 @@
     document.querySelector("#terms-and-conditions").checked;
   )";
   EXPECT_FALSE(content::EvalJs(shell(), javascript).ExtractBool());
-  Selector selector({R"(label[for="terms-and-conditions"])"},
-                    PseudoType::BEFORE);
+  Selector selector({R"(label[for="terms-and-conditions"])"});
+  selector.SetPseudoType(PseudoType::BEFORE);
   ClickOrTapElement(selector, ClickType::CLICK);
   EXPECT_TRUE(content::EvalJs(shell(), javascript).ExtractBool());
 }
diff --git a/components/blocked_content/BUILD.gn b/components/blocked_content/BUILD.gn
index ffb87b2..abc2014e 100644
--- a/components/blocked_content/BUILD.gn
+++ b/components/blocked_content/BUILD.gn
@@ -42,7 +42,10 @@
 
 source_set("unit_tests") {
   testonly = true
-  sources = [ "safe_browsing_triggered_popup_blocker_unittest.cc" ]
+  sources = [
+    "popup_blocker_tab_helper_unittest.cc",
+    "safe_browsing_triggered_popup_blocker_unittest.cc",
+  ]
   deps = [
     ":blocked_content",
     "//base",
diff --git a/components/blocked_content/popup_blocker_tab_helper_unittest.cc b/components/blocked_content/popup_blocker_tab_helper_unittest.cc
new file mode 100644
index 0000000..120c0df
--- /dev/null
+++ b/components/blocked_content/popup_blocker_tab_helper_unittest.cc
@@ -0,0 +1,228 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/blocked_content/popup_blocker_tab_helper.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "components/blocked_content/popup_navigation_delegate.h"
+#include "components/blocked_content/safe_browsing_triggered_popup_blocker.h"
+#include "components/blocked_content/url_list_manager.h"
+#include "components/content_settings/browser/tab_specific_content_settings.h"
+#include "components/content_settings/browser/test_tab_specific_content_settings_delegate.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "content/public/test/test_renderer_host.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/public/mojom/window_features/window_features.mojom.h"
+#include "ui/base/window_open_disposition.h"
+
+namespace blocked_content {
+namespace {
+using testing::Pair;
+using testing::UnorderedElementsAre;
+
+constexpr char kUrl1[] = "http://example1.test";
+constexpr char kUrl2[] = "http://example2.test";
+
+// Observer which allows retrieving a map of all the blocked URLs.
+class BlockedUrlListObserver : public UrlListManager::Observer {
+ public:
+  explicit BlockedUrlListObserver(PopupBlockerTabHelper* helper) {
+    observer_.Add(helper->manager());
+  }
+  // UrlListManager::Observer:
+  void BlockedUrlAdded(int32_t id, const GURL& url) override {
+    blocked_urls_.insert({id, url});
+  }
+
+  const std::map<int32_t, GURL>& blocked_urls() const { return blocked_urls_; }
+
+ private:
+  std::map<int32_t, GURL> blocked_urls_;
+  ScopedObserver<UrlListManager, UrlListManager::Observer> observer_{this};
+};
+
+// Struct used to hold results from calls on TestPopupNavigationDelegate since
+// the delegate will be destroyed on calls to ShowBlockedPopup().
+struct ResultHolder {
+  bool did_navigate = false;
+  blink::mojom::WindowFeatures navigation_window_features;
+  base::Optional<WindowOpenDisposition> navigation_disposition;
+  int total_popups_blocked_on_page = 0;
+};
+
+// Test delegate which stores results of calls in a ResultHolder.
+class TestPopupNavigationDelegate : public PopupNavigationDelegate {
+ public:
+  explicit TestPopupNavigationDelegate(const GURL& url,
+                                       ResultHolder* result_holder)
+      : url_(url), result_holder_(result_holder) {}
+
+  // PopupNavigationDelegate:
+  content::RenderFrameHost* GetOpener() override { return nullptr; }
+  bool GetOriginalUserGesture() override { return false; }
+  const GURL& GetURL() override { return url_; }
+
+  NavigateResult NavigateWithGesture(
+      const blink::mojom::WindowFeatures& window_features,
+      base::Optional<WindowOpenDisposition> updated_disposition) override {
+    result_holder_->did_navigate = true;
+    result_holder_->navigation_window_features = window_features;
+    result_holder_->navigation_disposition = updated_disposition;
+    return NavigateResult();
+  }
+
+  void OnPopupBlocked(content::WebContents* web_contents,
+                      int total_popups_blocked_on_page) override {
+    result_holder_->total_popups_blocked_on_page = total_popups_blocked_on_page;
+  }
+
+ private:
+  const GURL url_;
+  ResultHolder* result_holder_;
+};
+}  // namespace
+
+class PopupBlockerTabHelperTest : public content::RenderViewHostTestHarness {
+ public:
+  ~PopupBlockerTabHelperTest() override { settings_map_->ShutdownOnUIThread(); }
+
+  // content::RenderViewHostTestHarness:
+  void SetUp() override {
+    content::RenderViewHostTestHarness::SetUp();
+    // Make sure the SafeBrowsingTriggeredPopupBlocker is not created.
+    feature_list_.InitAndDisableFeature(kAbusiveExperienceEnforce);
+
+    HostContentSettingsMap::RegisterProfilePrefs(pref_service_.registry());
+    settings_map_ = base::MakeRefCounted<HostContentSettingsMap>(
+        &pref_service_, false, false, false, false);
+    content_settings::TabSpecificContentSettings::CreateForWebContents(
+        web_contents(),
+        std::make_unique<
+            content_settings::TestTabSpecificContentSettingsDelegate>(
+            /*prefs=*/nullptr, settings_map_.get()));
+
+    PopupBlockerTabHelper::CreateForWebContents(web_contents());
+    helper_ = PopupBlockerTabHelper::FromWebContents(web_contents());
+  }
+
+  PopupBlockerTabHelper* helper() { return helper_; }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+  PopupBlockerTabHelper* helper_ = nullptr;
+  sync_preferences::TestingPrefServiceSyncable pref_service_;
+  scoped_refptr<HostContentSettingsMap> settings_map_;
+};
+
+TEST_F(PopupBlockerTabHelperTest, BlocksAndShowsPopup) {
+  BlockedUrlListObserver observer(helper());
+  ResultHolder result;
+  blink::mojom::WindowFeatures window_features;
+  window_features.has_x = true;
+  helper()->AddBlockedPopup(
+      std::make_unique<TestPopupNavigationDelegate>(GURL(kUrl1), &result),
+      window_features, PopupBlockType::kNoGesture);
+  EXPECT_EQ(result.total_popups_blocked_on_page, 1);
+  EXPECT_FALSE(result.did_navigate);
+  EXPECT_THAT(observer.blocked_urls(),
+              UnorderedElementsAre(Pair(0, GURL(kUrl1))));
+
+  helper()->ShowBlockedPopup(0, WindowOpenDisposition::NEW_FOREGROUND_TAB);
+  EXPECT_TRUE(result.did_navigate);
+  EXPECT_TRUE(result.navigation_window_features.has_x);
+  EXPECT_EQ(result.navigation_disposition,
+            WindowOpenDisposition::NEW_FOREGROUND_TAB);
+}
+
+TEST_F(PopupBlockerTabHelperTest, MultiplePopups) {
+  BlockedUrlListObserver observer(helper());
+  ResultHolder result1;
+  helper()->AddBlockedPopup(
+      std::make_unique<TestPopupNavigationDelegate>(GURL(kUrl1), &result1),
+      blink::mojom::WindowFeatures(), PopupBlockType::kNoGesture);
+  EXPECT_EQ(result1.total_popups_blocked_on_page, 1);
+  EXPECT_THAT(observer.blocked_urls(),
+              UnorderedElementsAre(Pair(0, GURL(kUrl1))));
+  EXPECT_EQ(helper()->GetBlockedPopupsCount(), 1u);
+
+  ResultHolder result2;
+  helper()->AddBlockedPopup(
+      std::make_unique<TestPopupNavigationDelegate>(GURL(kUrl2), &result2),
+      blink::mojom::WindowFeatures(), PopupBlockType::kNoGesture);
+  EXPECT_EQ(result2.total_popups_blocked_on_page, 2);
+  EXPECT_THAT(observer.blocked_urls(),
+              UnorderedElementsAre(Pair(0, GURL(kUrl1)), Pair(1, GURL(kUrl2))));
+  EXPECT_EQ(helper()->GetBlockedPopupsCount(), 2u);
+
+  helper()->ShowBlockedPopup(1, WindowOpenDisposition::NEW_FOREGROUND_TAB);
+  EXPECT_EQ(helper()->GetBlockedPopupsCount(), 1u);
+  EXPECT_TRUE(result2.did_navigate);
+  EXPECT_EQ(result2.navigation_disposition,
+            WindowOpenDisposition::NEW_FOREGROUND_TAB);
+  EXPECT_FALSE(result1.did_navigate);
+
+  helper()->ShowBlockedPopup(0, WindowOpenDisposition::CURRENT_TAB);
+  EXPECT_EQ(helper()->GetBlockedPopupsCount(), 0u);
+  EXPECT_TRUE(result1.did_navigate);
+  EXPECT_FALSE(result1.navigation_disposition.has_value());
+}
+
+TEST_F(PopupBlockerTabHelperTest, DoesNotShowPopupWithInvalidID) {
+  ResultHolder result;
+  helper()->AddBlockedPopup(
+      std::make_unique<TestPopupNavigationDelegate>(GURL(kUrl1), &result),
+      blink::mojom::WindowFeatures(), PopupBlockType::kNoGesture);
+  EXPECT_EQ(helper()->GetBlockedPopupsCount(), 1u);
+
+  // Invalid ID should not do anything.
+  helper()->ShowBlockedPopup(1, WindowOpenDisposition::NEW_FOREGROUND_TAB);
+  EXPECT_EQ(helper()->GetBlockedPopupsCount(), 1u);
+  EXPECT_FALSE(result.did_navigate);
+
+  helper()->ShowBlockedPopup(0, WindowOpenDisposition::NEW_FOREGROUND_TAB);
+  EXPECT_EQ(helper()->GetBlockedPopupsCount(), 0u);
+  EXPECT_TRUE(result.did_navigate);
+}
+
+TEST_F(PopupBlockerTabHelperTest, SetsContentSettingsPopupState) {
+  auto* content_settings =
+      content_settings::TabSpecificContentSettings::FromWebContents(
+          web_contents());
+  EXPECT_FALSE(content_settings->IsContentBlocked(ContentSettingsType::POPUPS));
+
+  ResultHolder result;
+  helper()->AddBlockedPopup(
+      std::make_unique<TestPopupNavigationDelegate>(GURL(kUrl1), &result),
+      blink::mojom::WindowFeatures(), PopupBlockType::kNoGesture);
+  EXPECT_TRUE(content_settings->IsContentBlocked(ContentSettingsType::POPUPS));
+
+  helper()->AddBlockedPopup(
+      std::make_unique<TestPopupNavigationDelegate>(GURL(kUrl2), &result),
+      blink::mojom::WindowFeatures(), PopupBlockType::kNoGesture);
+  EXPECT_TRUE(content_settings->IsContentBlocked(ContentSettingsType::POPUPS));
+
+  helper()->ShowBlockedPopup(0, WindowOpenDisposition::NEW_FOREGROUND_TAB);
+  EXPECT_TRUE(content_settings->IsContentBlocked(ContentSettingsType::POPUPS));
+
+  helper()->ShowBlockedPopup(1, WindowOpenDisposition::NEW_FOREGROUND_TAB);
+  EXPECT_FALSE(content_settings->IsContentBlocked(ContentSettingsType::POPUPS));
+}
+
+TEST_F(PopupBlockerTabHelperTest, ClearsContentSettingsPopupStateOnNavigation) {
+  auto* content_settings =
+      content_settings::TabSpecificContentSettings::FromWebContents(
+          web_contents());
+
+  ResultHolder result;
+  helper()->AddBlockedPopup(
+      std::make_unique<TestPopupNavigationDelegate>(GURL(kUrl1), &result),
+      blink::mojom::WindowFeatures(), PopupBlockType::kNoGesture);
+  EXPECT_TRUE(content_settings->IsContentBlocked(ContentSettingsType::POPUPS));
+
+  NavigateAndCommit(GURL(kUrl2));
+  EXPECT_FALSE(content_settings->IsContentBlocked(ContentSettingsType::POPUPS));
+}
+
+}  // namespace blocked_content
diff --git a/components/browser_ui/share/DEPS b/components/browser_ui/share/DEPS
index b7c84e1..7d3ee13 100644
--- a/components/browser_ui/share/DEPS
+++ b/components/browser_ui/share/DEPS
@@ -1,6 +1,5 @@
 include_rules = [
   "+components/dom_distiller/core/android",
   "+content/public/android",
-  "+content/public/test/android/javatests",
   "+ui/android",
 ]
diff --git a/components/browser_ui/share/android/java/src/org/chromium/components/browser_ui/share/ShareImageFileUtilsTest.java b/components/browser_ui/share/android/java/src/org/chromium/components/browser_ui/share/ShareImageFileUtilsTest.java
index 9385dcb3..79298ba 100644
--- a/components/browser_ui/share/android/java/src/org/chromium/components/browser_ui/share/ShareImageFileUtilsTest.java
+++ b/components/browser_ui/share/android/java/src/org/chromium/components/browser_ui/share/ShareImageFileUtilsTest.java
@@ -20,7 +20,6 @@
 import android.support.test.filters.SmallTest;
 
 import androidx.core.content.FileProvider;
-import androidx.core.util.ObjectsCompat;
 
 import org.junit.Assert;
 import org.junit.Test;
@@ -35,8 +34,6 @@
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
-import org.chromium.content_public.browser.test.util.Criteria;
-import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.ui.base.Clipboard;
 import org.chromium.ui.test.util.DummyUiActivityTestCase;
 
@@ -135,13 +132,6 @@
                 getActivity(), TEST_IMAGE_DATA, fileExtension, imageCallback);
         imageCallback.waitForCallback(0, 1, WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
         Clipboard.getInstance().setImageUri(imageCallback.getImageUri());
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return ObjectsCompat.equals(
-                        Clipboard.getInstance().getImageUri(), imageCallback.getImageUri());
-            }
-        });
         return imageCallback.getImageUri();
     }
 
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/image_tiles/TileCoordinatorImpl.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/image_tiles/TileCoordinatorImpl.java
index de3f009..bf599b35 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/image_tiles/TileCoordinatorImpl.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/image_tiles/TileCoordinatorImpl.java
@@ -9,6 +9,7 @@
 
 import org.chromium.base.Callback;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -34,7 +35,15 @@
 
     @Override
     public void setTiles(List<ImageTile> tiles) {
+        // Determine if the old set of tiles have changed. If yes, show animation.
+        List<ImageTile> oldTiles = new ArrayList<>();
+        for (int i = 0; i < mModel.size(); i++) {
+            oldTiles.add(mModel.get(i));
+        }
+        boolean shouldAnimate = !oldTiles.isEmpty() && !oldTiles.equals(tiles);
+
         mModel.set(tiles);
-        mView.scrollToPosition(0);
+        mView.scrollToBeginning();
+        mView.showAnimation(shouldAnimate);
     }
 }
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/image_tiles/TileListView.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/image_tiles/TileListView.java
index eef43e0..25c5cbc 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/image_tiles/TileListView.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/image_tiles/TileListView.java
@@ -9,6 +9,7 @@
 import android.graphics.Rect;
 import android.view.View;
 import android.view.animation.AnimationUtils;
+import android.view.animation.LayoutAnimationController;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -31,6 +32,7 @@
     private final RecyclerView mView;
     private final RecyclerViewAdapter<TileViewHolder, Void> mAdapter;
     private final LinearLayoutManager mLayoutManager;
+    private final LayoutAnimationController mLayoutAnimationController;
     private final TileSizeSupplier mTileSizeSupplier;
 
     /** Constructor. */
@@ -54,8 +56,8 @@
         mView.setLayoutManager(mLayoutManager);
         mView.addItemDecoration(new ItemDecorationImpl(context));
         mView.setItemAnimator(null);
-        mView.setLayoutAnimation(
-                AnimationUtils.loadLayoutAnimation(context, R.anim.image_grid_enter));
+        mLayoutAnimationController =
+                AnimationUtils.loadLayoutAnimation(context, R.anim.image_grid_enter);
 
         mTileSizeSupplier = new TileSizeSupplier(context);
 
@@ -73,10 +75,23 @@
         return mView;
     }
 
-    /** Scrolls the recycler view to the given {@code position}. */
-    public void scrollToPosition(int position) {
-        mView.getLayoutManager().scrollToPosition(0);
-        mView.scheduleLayoutAnimation();
+    /** Scrolls to the beginning of the list if possible. */
+    void scrollToBeginning() {
+        if (mView.computeHorizontalScrollOffset() != 0) {
+            mView.getLayoutManager().scrollToPosition(0);
+        }
+    }
+
+    /**
+     * Called to show enter animation for the list items.
+     */
+    void showAnimation(boolean animate) {
+        if (animate) {
+            mView.setLayoutAnimation(mLayoutAnimationController);
+            mView.scheduleLayoutAnimation();
+        } else {
+            mView.setLayoutAnimation(null);
+        }
     }
 
     private class ItemDecorationImpl extends ItemDecoration {
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
index fbb6b80..2f60471 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
@@ -42,7 +42,6 @@
     public final CronetTestRule mTestRule = new CronetTestRule();
 
     private static final String TAG = QuicTest.class.getSimpleName();
-    private static final String QUIC_PROTOCOL_STRING_PREFIX = "http/2+quic/";
     private ExperimentalCronetEngine.Builder mBuilder;
 
     @Before
@@ -300,6 +299,7 @@
 
     // Helper method to assert that the request is negotiated over QUIC.
     private void assertIsQuic(UrlResponseInfo responseInfo) {
-        assertTrue(responseInfo.getNegotiatedProtocol().startsWith(QUIC_PROTOCOL_STRING_PREFIX));
+        assertTrue(responseInfo.getNegotiatedProtocol().startsWith("http/2+quic")
+                || responseInfo.getNegotiatedProtocol().startsWith("h3"));
     }
 }
diff --git a/components/cronet/android/test/smoketests/src/org/chromium/net/smoke/QuicTest.java b/components/cronet/android/test/smoketests/src/org/chromium/net/smoke/QuicTest.java
index cf0eac7..5c9721e3 100644
--- a/components/cronet/android/test/smoketests/src/org/chromium/net/smoke/QuicTest.java
+++ b/components/cronet/android/test/smoketests/src/org/chromium/net/smoke/QuicTest.java
@@ -72,7 +72,8 @@
             requestBuilder.build().start();
             callback.blockForDone();
             NativeCronetTestRule.assertSuccessfulNonEmptyResponse(callback, urlString);
-            if (callback.getResponseInfo().getNegotiatedProtocol().startsWith("http/2+quic/")) {
+            if (callback.getResponseInfo().getNegotiatedProtocol().startsWith("http/2+quic")
+                    || callback.getResponseInfo().getNegotiatedProtocol().startsWith("h3")) {
                 quicNegotiated = true;
                 break;
             }
diff --git a/components/download/public/common/download_schedule.cc b/components/download/public/common/download_schedule.cc
index d3d96dc..7a3672c 100644
--- a/components/download/public/common/download_schedule.cc
+++ b/components/download/public/common/download_schedule.cc
@@ -14,6 +14,8 @@
 DownloadSchedule::DownloadSchedule(base::Optional<base::Time> start_time)
     : only_on_wifi_(false), start_time_(start_time) {}
 
+DownloadSchedule::DownloadSchedule(const DownloadSchedule&) = default;
+
 DownloadSchedule::~DownloadSchedule() = default;
 
 }  // namespace download
diff --git a/components/download/public/common/download_schedule.h b/components/download/public/common/download_schedule.h
index c9bf8623..4e57001 100644
--- a/components/download/public/common/download_schedule.h
+++ b/components/download/public/common/download_schedule.h
@@ -17,6 +17,7 @@
  public:
   explicit DownloadSchedule(bool only_on_wifi);
   explicit DownloadSchedule(base::Optional<base::Time> start_time);
+  DownloadSchedule(const DownloadSchedule&);
   ~DownloadSchedule();
 
   bool only_on_wifi() const { return only_on_wifi_; }
diff --git a/components/find_in_page/android/find_in_page_bridge.cc b/components/find_in_page/android/find_in_page_bridge.cc
index fac7ff2..2346f0d 100644
--- a/components/find_in_page/android/find_in_page_bridge.cc
+++ b/components/find_in_page/android/find_in_page_bridge.cc
@@ -36,7 +36,8 @@
   find_in_page::FindTabHelper::FromWebContents(web_contents_)
       ->StartFinding(
           base::android::ConvertJavaStringToUTF16(env, search_string),
-          forward_direction, case_sensitive);
+          forward_direction, case_sensitive,
+          true /* find_next_if_selection_matches */);
 }
 
 void FindInPageBridge::StopFinding(JNIEnv* env,
diff --git a/components/find_in_page/find_tab_helper.cc b/components/find_in_page/find_tab_helper.cc
index 136d31e7..a3beda3 100644
--- a/components/find_in_page/find_tab_helper.cc
+++ b/components/find_in_page/find_tab_helper.cc
@@ -45,6 +45,7 @@
 void FindTabHelper::StartFinding(base::string16 search_string,
                                  bool forward_direction,
                                  bool case_sensitive,
+                                 bool find_next_if_selection_matches,
                                  bool run_synchronously_for_testing) {
   // Remove the carriage return character, which generally isn't in web content.
   const base::char16 kInvalidChars[] = {'\r', 0};
@@ -62,18 +63,13 @@
   // Keep track of the previous search.
   previous_find_text_ = find_text_;
 
-  // This is a FindNext operation if we are searching for the same text again,
-  // or if the passed in search text is empty (FindNext keyboard shortcut). The
-  // exception to this is if the Find was aborted (then we don't want FindNext
-  // because the highlighting has been cleared and we need it to reappear). We
-  // therefore treat FindNext after an aborted Find operation as a full fledged
-  // Find.
-  bool find_next = (find_text_ == search_string || search_string.empty()) &&
-                   (last_search_case_sensitive_ == case_sensitive) &&
-                   !find_op_aborted_;
+  // NB: search_string will be empty when using the FindNext keyboard shortcut.
+  bool new_session = (find_text_ != search_string && !search_string.empty()) ||
+                     (last_search_case_sensitive_ != case_sensitive) ||
+                     find_op_aborted_;
 
   current_find_request_id_ = find_request_id_counter_++;
-  if (!find_next)
+  if (new_session)
     current_find_session_id_ = current_find_request_id_;
 
   if (!search_string.empty())
@@ -89,7 +85,8 @@
   auto options = blink::mojom::FindOptions::New();
   options->forward = forward_direction;
   options->match_case = case_sensitive;
-  options->find_next = find_next;
+  options->new_session = new_session;
+  options->find_next_if_selection_matches = find_next_if_selection_matches;
   options->run_synchronously_for_testing = run_synchronously_for_testing;
   web_contents_->Find(current_find_request_id_, find_text_, std::move(options));
 }
diff --git a/components/find_in_page/find_tab_helper.h b/components/find_in_page/find_tab_helper.h
index deba2834..73586ea 100644
--- a/components/find_in_page/find_tab_helper.h
+++ b/components/find_in_page/find_tab_helper.h
@@ -46,9 +46,14 @@
   // function does not block while a search is in progress. The controller will
   // receive the results through the notification mechanism. See Observe(...)
   // for details.
+  //
+  // If |find_next_if_selection_matches| is true and the search results in an
+  // exact match of the selection, keep searching. It should generally be set to
+  // true unless you're starting a new find based on the selection.
   void StartFinding(base::string16 search_string,
                     bool forward_direction,
                     bool case_sensitive,
+                    bool find_next_if_selection_matches,
                     bool run_synchronously_for_testing = false);
 
   // Stops the current Find operation.
diff --git a/components/gcm_driver/gcm_client_impl.cc b/components/gcm_driver/gcm_client_impl.cc
index 1d0c9ced..9b37fd0 100644
--- a/components/gcm_driver/gcm_client_impl.cc
+++ b/components/gcm_driver/gcm_client_impl.cc
@@ -799,8 +799,6 @@
   // TODO(crbug.com/1081149): Implement proper error handling.
   // TODO(fgorski): Ignoring the write result for now to make sure
   // sync_intergration_tests are not broken.
-  base::UmaHistogramBoolean(
-      "GCM.IgnoredWriteResult." + operation_suffix_for_uma, success);
 }
 
 void GCMClientImpl::DestroyStoreCallback(bool success) {
diff --git a/components/gcm_driver/instance_id/instance_id_impl.cc b/components/gcm_driver/instance_id/instance_id_impl.cc
index db93f58..139dcb9 100644
--- a/components/gcm_driver/instance_id/instance_id_impl.cc
+++ b/components/gcm_driver/instance_id/instance_id_impl.cc
@@ -232,7 +232,6 @@
 void InstanceIDImpl::EnsureIDGenerated() {
   if (!id_.empty())
     return;
-  UMA_HISTOGRAM_BOOLEAN("InstanceID.GeneratedNewID", true);
 
   // Now produce the ID in the following steps:
 
diff --git a/components/infobars/content/BUILD.gn b/components/infobars/content/BUILD.gn
new file mode 100644
index 0000000..6be0c415
--- /dev/null
+++ b/components/infobars/content/BUILD.gn
@@ -0,0 +1,18 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+static_library("content") {
+  sources = [
+    "content_infobar_manager.cc",
+    "content_infobar_manager.h",
+  ]
+
+  public_deps = [
+    "//base",
+    "//components/infobars/core",
+    "//content/public/browser",
+    "//content/public/common",
+    "//ui/base",
+  ]
+}
diff --git a/components/infobars/content/DEPS b/components/infobars/content/DEPS
new file mode 100644
index 0000000..c24130e
--- /dev/null
+++ b/components/infobars/content/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+content/public/browser",
+  "+content/public/common",
+]
diff --git a/components/infobars/content/content_infobar_manager.cc b/components/infobars/content/content_infobar_manager.cc
new file mode 100644
index 0000000..d93801b
--- /dev/null
+++ b/components/infobars/content/content_infobar_manager.cc
@@ -0,0 +1,115 @@
+// Copyright (c) 2013 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/infobars/content/content_infobar_manager.h"
+
+#include "base/command_line.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+#include "components/infobars/core/infobar.h"
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
+#include "ui/base/page_transition_types.h"
+
+namespace infobars {
+
+// static
+InfoBarDelegate::NavigationDetails
+ContentInfoBarManager::NavigationDetailsFromLoadCommittedDetails(
+    const content::LoadCommittedDetails& details) {
+  InfoBarDelegate::NavigationDetails navigation_details;
+  navigation_details.entry_id = details.entry->GetUniqueID();
+  navigation_details.is_navigation_to_different_page =
+      details.is_navigation_to_different_page();
+  navigation_details.did_replace_entry = details.did_replace_entry;
+  const ui::PageTransition transition = details.entry->GetTransitionType();
+  navigation_details.is_reload =
+      ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD);
+  navigation_details.is_redirect = ui::PageTransitionIsRedirect(transition);
+  return navigation_details;
+}
+
+// static
+content::WebContents* ContentInfoBarManager::WebContentsFromInfoBar(
+    InfoBar* infobar) {
+  if (!infobar || !infobar->owner())
+    return nullptr;
+  ContentInfoBarManager* infobar_manager =
+      static_cast<ContentInfoBarManager*>(infobar->owner());
+  return infobar_manager->web_contents();
+}
+
+ContentInfoBarManager::ContentInfoBarManager(content::WebContents* web_contents)
+    : content::WebContentsObserver(web_contents), ignore_next_reload_(false) {
+  DCHECK(web_contents);
+  // Infobar animations cause viewport resizes. Disable them for automated
+  // tests, since they could lead to flakiness.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableAutomation))
+    set_animations_enabled(false);
+}
+
+ContentInfoBarManager::~ContentInfoBarManager() {
+  ShutDown();
+}
+
+int ContentInfoBarManager::GetActiveEntryID() {
+  content::NavigationEntry* active_entry =
+      web_contents()->GetController().GetActiveEntry();
+  return active_entry ? active_entry->GetUniqueID() : 0;
+}
+
+std::unique_ptr<InfoBar> ContentInfoBarManager::CreateConfirmInfoBar(
+    std::unique_ptr<ConfirmInfoBarDelegate> delegate) {
+  NOTREACHED();
+  return nullptr;
+}
+
+void ContentInfoBarManager::RenderProcessGone(base::TerminationStatus status) {
+  RemoveAllInfoBars(true);
+}
+
+void ContentInfoBarManager::DidStartNavigation(
+    content::NavigationHandle* navigation_handle) {
+  if (!navigation_handle->IsInMainFrame() ||
+      navigation_handle->IsSameDocument()) {
+    return;
+  }
+
+  ignore_next_reload_ = false;
+}
+
+void ContentInfoBarManager::NavigationEntryCommitted(
+    const content::LoadCommittedDetails& load_details) {
+  const bool ignore =
+      ignore_next_reload_ &&
+      ui::PageTransitionCoreTypeIs(load_details.entry->GetTransitionType(),
+                                   ui::PAGE_TRANSITION_RELOAD);
+  ignore_next_reload_ = false;
+  if (!ignore)
+    OnNavigation(NavigationDetailsFromLoadCommittedDetails(load_details));
+}
+
+void ContentInfoBarManager::WebContentsDestroyed() {
+  // Subclasses may override this method to destroy this object, so don't do
+  // anything here.
+}
+
+void ContentInfoBarManager::OpenURL(const GURL& url,
+                                    WindowOpenDisposition disposition) {
+  // A normal user click on an infobar URL will result in a CURRENT_TAB
+  // disposition; turn that into a NEW_FOREGROUND_TAB so that we don't end up
+  // smashing the page the user is looking at.
+  web_contents()->OpenURL(
+      content::OpenURLParams(url, content::Referrer(),
+                             (disposition == WindowOpenDisposition::CURRENT_TAB)
+                                 ? WindowOpenDisposition::NEW_FOREGROUND_TAB
+                                 : disposition,
+                             ui::PAGE_TRANSITION_LINK, false));
+
+}  // namespace infobars
+
+}  // namespace infobars
diff --git a/components/infobars/content/content_infobar_manager.h b/components/infobars/content/content_infobar_manager.h
new file mode 100644
index 0000000..f9c1234
--- /dev/null
+++ b/components/infobars/content/content_infobar_manager.h
@@ -0,0 +1,88 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_INFOBARS_CONTENT_CONTENT_INFOBAR_MANAGER_H_
+#define COMPONENTS_INFOBARS_CONTENT_CONTENT_INFOBAR_MANAGER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "components/infobars/core/infobar_manager.h"
+#include "content/public/browser/reload_type.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+#include "ui/base/window_open_disposition.h"
+
+namespace content {
+struct LoadCommittedDetails;
+class WebContents;
+}  // namespace content
+
+namespace infobars {
+
+class InfoBar;
+
+// Associates a WebContents to an InfoBarManager.
+// It manages the infobar notifications and responds to navigation events.
+// By default the creation of confirm infobars is not supported. If embedders
+// wish to add such support, they should create a custom subclass of
+// ContentInfoBarManager that overrides CreateConfirmInfoBar().
+// This class is not itself a WebContentsUserData in order to support such
+// subclassing; it is expected that embedders will either have an instance of
+// this class as a member of their "Tab" objects or create a custom subclass
+// that is a WCUD.
+class ContentInfoBarManager : public InfoBarManager,
+                              public content::WebContentsObserver {
+ public:
+  explicit ContentInfoBarManager(content::WebContents* web_contents);
+  ~ContentInfoBarManager() override;
+
+  static InfoBarDelegate::NavigationDetails
+  NavigationDetailsFromLoadCommittedDetails(
+      const content::LoadCommittedDetails& details);
+
+  // This function must only be called on infobars that are owned by a
+  // ContentInfoBarManager instance (or not owned at all, in which case this
+  // returns nullptr).
+  static content::WebContents* WebContentsFromInfoBar(InfoBar* infobar);
+
+  // Makes it so the next reload is ignored. That is, if the next commit is a
+  // reload then it is treated as if nothing happened and no infobars are
+  // attempted to be closed.
+  // This is useful for non-user triggered reloads that should not dismiss
+  // infobars. For example, instant may trigger a reload when the google URL
+  // changes.
+  void set_ignore_next_reload() { ignore_next_reload_ = true; }
+
+  // InfoBarManager:
+  // NOTE: By default this method is NOTREACHED() and returns nullptr.
+  // TODO(sdefresne): Change clients to invoke this on InfoBarManager
+  // and turn the method override private.
+  std::unique_ptr<InfoBar> CreateConfirmInfoBar(
+      std::unique_ptr<ConfirmInfoBarDelegate> delegate) override;
+  void OpenURL(const GURL& url, WindowOpenDisposition disposition) override;
+
+ private:
+  // InfoBarManager:
+  int GetActiveEntryID() override;
+
+  // content::WebContentsObserver:
+  void RenderProcessGone(base::TerminationStatus status) override;
+  void DidStartNavigation(
+      content::NavigationHandle* navigation_handle) override;
+  void NavigationEntryCommitted(
+      const content::LoadCommittedDetails& load_details) override;
+  void WebContentsDestroyed() override;
+
+  // See description in set_ignore_next_reload().
+  bool ignore_next_reload_;
+
+  DISALLOW_COPY_AND_ASSIGN(ContentInfoBarManager);
+};
+
+}  // namespace infobars
+
+#endif  // COMPONENTS_INFOBARS_CONTENT_CONTENT_INFOBAR_MANAGER_H_
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc
index b7b64fd..4858878 100644
--- a/components/omnibox/browser/omnibox_edit_model.cc
+++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -1330,7 +1330,6 @@
     return;
   }
 
-  bool call_controller_onchanged = true;
   inline_autocomplete_text_ = text;
   if (inline_autocomplete_text_.empty())
     view_->OnInlineAutocompleteTextCleared();
@@ -1356,15 +1355,13 @@
     // caret or selection correctly so the caret positioning we do here won't
     // matter.
     view_->SetWindowTextAndCaretPos(user_text, 0, false, true);
-  } else if (view_->OnInlineAutocompleteTextMaybeChanged(
-                 user_text + inline_autocomplete_text_, user_text.length())) {
-    call_controller_onchanged = false;
-  }
+  } else
+    view_->OnInlineAutocompleteTextMaybeChanged(
+        user_text + inline_autocomplete_text_, user_text.length());
 
   // We need to invoke OnChanged in case the destination url changed (as could
   // happen when control is toggled).
-  if (call_controller_onchanged)
-    OnChanged();
+  OnChanged();
 }
 
 bool OmniboxEditModel::OnAfterPossibleChange(
diff --git a/components/omnibox/browser/omnibox_view.cc b/components/omnibox/browser/omnibox_view.cc
index 24715f8..baed91d 100644
--- a/components/omnibox/browser/omnibox_view.cc
+++ b/components/omnibox/browser/omnibox_view.cc
@@ -19,14 +19,20 @@
 #include "components/omnibox/browser/location_bar_model.h"
 #include "components/omnibox/browser/omnibox_edit_controller.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
+#include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/common/omnibox_features.h"
 #include "extensions/common/constants.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
+
 #include "ui/gfx/paint_vector_icon.h"
+
 #endif
 
+OmniboxView::State::State() = default;
+OmniboxView::State::State(const State& state) = default;
+
 // static
 base::string16 OmniboxView::StripJavascriptSchemas(const base::string16& text) {
   const base::string16 kJsPrefix(
@@ -264,6 +270,8 @@
   state->keyword = model()->keyword();
   state->is_keyword_selected = model()->is_keyword_selected();
   GetSelectionBounds(&state->sel_start, &state->sel_end);
+  if (OmniboxFieldTrial::RichAutocompletionAutocompleteNonPrefix())
+    state->all_sel_length = GetAllSelectionsLength();
 }
 
 OmniboxView::StateChanges OmniboxView::GetStateChanges(const State& before,
@@ -294,8 +302,14 @@
   // sure the caret, which should be after any insertion, hasn't moved
   // forward of the old selection start.)
   state_changes.just_deleted_text =
-      (before.text.length() > after.text.length()) &&
-      (after.sel_start <= std::min(before.sel_start, before.sel_end));
+      before.text.length() > after.text.length() &&
+      after.sel_start <= std::min(before.sel_start, before.sel_end);
+  if (OmniboxFieldTrial::RichAutocompletionAutocompleteNonPrefix()) {
+    state_changes.just_deleted_text =
+        state_changes.just_deleted_text &&
+        after.sel_start <=
+            std::max(before.sel_start, before.sel_end) - before.all_sel_length;
+  }
 
   return state_changes;
 }
diff --git a/components/omnibox/browser/omnibox_view.h b/components/omnibox/browser/omnibox_view.h
index a79dd20..bc1398c5 100644
--- a/components/omnibox/browser/omnibox_view.h
+++ b/components/omnibox/browser/omnibox_view.h
@@ -103,11 +103,15 @@
                            bool update_popup);
 
   // Sets the window text and the caret position. |notify_text_changed| is true
-  // if the model should be notified of the change.
-  virtual void SetWindowTextAndCaretPos(const base::string16& text,
-                                        size_t caret_pos,
-                                        bool update_popup,
-                                        bool notify_text_changed) = 0;
+  // if the model should be notified of the change. If rich autocompletion is
+  // enabled, |additional_text| is displayed in a non-editable views::Label
+  // adjacent to the omnibox.
+  virtual void SetWindowTextAndCaretPos(
+      const base::string16& text,
+      size_t caret_pos,
+      bool update_popup,
+      bool notify_text_changed,
+      const base::string16& additional_text = base::string16()) = 0;
 
   // Sets the caret position. Removes any selection. Clamps the requested caret
   // position to the length of the current text.
@@ -126,6 +130,11 @@
   // to the current cursor position.
   virtual void GetSelectionBounds(size_t* start, size_t* end) const = 0;
 
+  // Returns the sum of all selections' lengths. This is used to detect when
+  // the user has deleted text, and therefore, their input should not be
+  // autocompleted.
+  virtual size_t GetAllSelectionsLength() const = 0;
+
   // Selects all the text in the edit.  Use this in place of SetSelAll() to
   // avoid selecting the "phantom newline" at the end of the edit.
   virtual void SelectAll(bool reversed) = 0;
@@ -168,11 +177,17 @@
                                            bool notify_text_changed) = 0;
 
   // Called when the inline autocomplete text in the model may have changed.
-  // |display_text| is the new text to show; |user_text_length| is the length of
-  // the user input portion of that (so, up to but not including the inline
-  // autocompletion).  Returns whether the display text actually changed.
-  virtual bool OnInlineAutocompleteTextMaybeChanged(
-      const base::string16& display_text, size_t user_text_length) = 0;
+  // |display_text| is the new text to show. |user_text_start| and
+  // |user_text_length| are the start position and length of the user input
+  // portion of the text (not including the inline autocompletion or prefix
+  // inline autocompletion). If rich autocompletion is enabled,
+  // |additional_text| is displayed in a non-editable views::Label adjacent to
+  // the omnibox.
+  virtual void OnInlineAutocompleteTextMaybeChanged(
+      const base::string16& display_text,
+      size_t user_text_length,
+      size_t user_text_start = 0,
+      const base::string16& additional_text = base::string16()) = 0;
 
   // Called when the inline autocomplete text in the model has been cleared.
   virtual void OnInlineAutocompleteTextCleared() = 0;
@@ -251,6 +266,10 @@
     bool is_keyword_selected;
     size_t sel_start;
     size_t sel_end;
+    size_t all_sel_length;
+
+    State();
+    State(const State& state);
   };
 
   OmniboxView(OmniboxEditController* controller,
diff --git a/components/omnibox/browser/omnibox_view_unittest.cc b/components/omnibox/browser/omnibox_view_unittest.cc
index 1d9a030..fa1bad6 100644
--- a/components/omnibox/browser/omnibox_view_unittest.cc
+++ b/components/omnibox/browser/omnibox_view_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "build/build_config.h"
 #include "components/bookmarks/browser/bookmark_model.h"
@@ -20,6 +21,7 @@
 #include "components/omnibox/browser/test_omnibox_edit_controller.h"
 #include "components/omnibox/browser/test_omnibox_edit_model.h"
 #include "components/omnibox/browser/test_omnibox_view.h"
+#include "components/omnibox/common/omnibox_features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/favicon_size.h"
@@ -210,4 +212,148 @@
 }
 #endif  // !defined(OS_IOS)
 
+// Tests GetStateChanges correctly determines if text was deleted.
+TEST_F(OmniboxViewTest, GetStateChanges_DeletedText) {
+  {
+    // Continuing autocompletion
+    auto state_before =
+        TestOmniboxView::CreateState("google.com", 10, 3, 0);  // goo[gle.com]
+    auto state_after = TestOmniboxView::CreateState("goog", 4, 4, 0);  // goog|
+    auto state_changes = view()->GetStateChanges(state_before, state_after);
+    EXPECT_FALSE(state_changes.just_deleted_text);
+  }
+  {
+    // Typing not the autocompletion
+    auto state_before =
+        TestOmniboxView::CreateState("google.com", 1, 10, 0);  // g[oogle.com]
+    auto state_after = TestOmniboxView::CreateState("gi", 2, 2, 0);  // gi|
+    auto state_changes = view()->GetStateChanges(state_before, state_after);
+    EXPECT_FALSE(state_changes.just_deleted_text);
+  }
+  {
+    // Deleting autocompletion
+    auto state_before =
+        TestOmniboxView::CreateState("google.com", 1, 10, 0);  // g[oogle.com]
+    auto state_after = TestOmniboxView::CreateState("g", 1, 1, 0);  // g|
+    auto state_changes = view()->GetStateChanges(state_before, state_after);
+    EXPECT_TRUE(state_changes.just_deleted_text);
+  }
+  {
+    // Inserting
+    auto state_before =
+        TestOmniboxView::CreateState("goole.com", 3, 3, 0);  // goo|le.com
+    auto state_after =
+        TestOmniboxView::CreateState("google.com", 4, 4, 0);  // goog|le.com
+    auto state_changes = view()->GetStateChanges(state_before, state_after);
+    EXPECT_FALSE(state_changes.just_deleted_text);
+  }
+  {
+    // Deleting
+    auto state_before =
+        TestOmniboxView::CreateState("googgle.com", 5, 5, 0);  // googg|le.com
+    auto state_after =
+        TestOmniboxView::CreateState("google.com", 4, 4, 0);  // goog|le.com
+    auto state_changes = view()->GetStateChanges(state_before, state_after);
+    EXPECT_TRUE(state_changes.just_deleted_text);
+  }
+  {
+    // Replacing
+    auto state_before =
+        TestOmniboxView::CreateState("goojle.com", 3, 4, 0);  // goo[j]le.com
+    auto state_after =
+        TestOmniboxView::CreateState("google.com", 4, 4, 0);  // goog|le.com
+    auto state_changes = view()->GetStateChanges(state_before, state_after);
+    EXPECT_FALSE(state_changes.just_deleted_text);
+  }
+}
+
+// Tests GetStateChanges correctly determines if text was deleted.
+TEST_F(OmniboxViewTest, GetStateChanges_DeletedText_RichAutocompletion) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeatureWithParameters(
+      omnibox::kRichAutocompletion,
+      {{OmniboxFieldTrial::kRichAutocompletionAutocompleteNonPrefix, "true"}});
+
+  // Cases with single selection
+
+  {
+    // Continuing autocompletion
+    auto state_before =
+        TestOmniboxView::CreateState("google.com", 10, 3, 7);  // goo[gle.com]
+    auto state_after = TestOmniboxView::CreateState("goog", 4, 4, 0);  // goog|
+    auto state_changes = view()->GetStateChanges(state_before, state_after);
+    EXPECT_FALSE(state_changes.just_deleted_text);
+  }
+  {
+    // Typing not the autocompletion
+    auto state_before =
+        TestOmniboxView::CreateState("google.com", 1, 10, 9);  // g[oogle.com]
+    auto state_after = TestOmniboxView::CreateState("gi", 2, 2, 0);  // gi|
+    auto state_changes = view()->GetStateChanges(state_before, state_after);
+    EXPECT_FALSE(state_changes.just_deleted_text);
+  }
+  {
+    // Deleting autocompletion
+    auto state_before =
+        TestOmniboxView::CreateState("google.com", 1, 10, 9);  // g[oogle.com]
+    auto state_after = TestOmniboxView::CreateState("g", 1, 1, 0);  // g|
+    auto state_changes = view()->GetStateChanges(state_before, state_after);
+    EXPECT_TRUE(state_changes.just_deleted_text);
+  }
+  {
+    // Inserting
+    auto state_before =
+        TestOmniboxView::CreateState("goole.com", 3, 3, 6);  // goo|le.com
+    auto state_after =
+        TestOmniboxView::CreateState("google.com", 4, 4, 0);  // goog|le.com
+    auto state_changes = view()->GetStateChanges(state_before, state_after);
+    EXPECT_FALSE(state_changes.just_deleted_text);
+  }
+  {
+    // Deleting
+    auto state_before =
+        TestOmniboxView::CreateState("googgle.com", 5, 5, 0);  // googg|le.com
+    auto state_after =
+        TestOmniboxView::CreateState("google.com", 4, 4, 0);  // goog|le.com
+    auto state_changes = view()->GetStateChanges(state_before, state_after);
+    EXPECT_TRUE(state_changes.just_deleted_text);
+  }
+  {
+    // Replacing
+    auto state_before =
+        TestOmniboxView::CreateState("goojle.com", 3, 4, 1);  // goo[j]le.com
+    auto state_after =
+        TestOmniboxView::CreateState("google.com", 4, 4, 0);  // goog|le.com
+    auto state_changes = view()->GetStateChanges(state_before, state_after);
+    EXPECT_FALSE(state_changes.just_deleted_text);
+  }
+
+  // Cases with multiselection
+
+  {
+    // Continuing autocompletion with multiselection
+    auto state_before =
+        TestOmniboxView::CreateState("google.com", 4, 10, 7);  // [g]oog[le.com]
+    auto state_after = TestOmniboxView::CreateState("oogl", 4, 4, 0);  // oogl|
+    auto state_changes = view()->GetStateChanges(state_before, state_after);
+    EXPECT_FALSE(state_changes.just_deleted_text);
+  }
+  {
+    // Typing not the autocompletion with multiselection
+    auto state_before =
+        TestOmniboxView::CreateState("google.com", 4, 10, 7);  // [g]oog[le.com]
+    auto state_after = TestOmniboxView::CreateState("oogm", 4, 4, 0);  // oogm|
+    auto state_changes = view()->GetStateChanges(state_before, state_after);
+    EXPECT_FALSE(state_changes.just_deleted_text);
+  }
+  {
+    // Deleting autocompletion with multiselection
+    auto state_before =
+        TestOmniboxView::CreateState("google.com", 4, 10, 7);  // [g]oog[le.com]
+    auto state_after = TestOmniboxView::CreateState("oog", 3, 3, 0);  // oog|
+    auto state_changes = view()->GetStateChanges(state_before, state_after);
+    EXPECT_TRUE(state_changes.just_deleted_text);
+  }
+}
+
 }  // namespace
diff --git a/components/omnibox/browser/test_omnibox_view.cc b/components/omnibox/browser/test_omnibox_view.cc
index 74e9460..26e1fc8c 100644
--- a/components/omnibox/browser/test_omnibox_view.cc
+++ b/components/omnibox/browser/test_omnibox_view.cc
@@ -8,6 +8,21 @@
 
 #include "ui/gfx/native_widget_types.h"
 
+// static
+OmniboxView::State TestOmniboxView::CreateState(std::string text,
+                                                size_t sel_start,
+                                                size_t sel_end,
+                                                size_t all_sel_length) {
+  OmniboxView::State state;
+  state.text = base::UTF8ToUTF16(text);
+  state.keyword = base::string16();
+  state.is_keyword_selected = false;
+  state.sel_start = sel_start;
+  state.sel_end = sel_end;
+  state.all_sel_length = all_sel_length;
+  return state;
+}
+
 void TestOmniboxView::SetModel(std::unique_ptr<OmniboxEditModel> model) {
   model_ = std::move(model);
 }
@@ -16,10 +31,12 @@
   return text_;
 }
 
-void TestOmniboxView::SetWindowTextAndCaretPos(const base::string16& text,
-                                               size_t caret_pos,
-                                               bool update_popup,
-                                               bool notify_text_changed) {
+void TestOmniboxView::SetWindowTextAndCaretPos(
+    const base::string16& text,
+    size_t caret_pos,
+    bool update_popup,
+    bool notify_text_changed,
+    const base::string16& additional_text) {
   text_ = text;
   selection_ = gfx::Range(caret_pos);
 }
@@ -33,6 +50,10 @@
   *end = selection_.end();
 }
 
+size_t TestOmniboxView::GetAllSelectionsLength() const {
+  return 0;
+}
+
 void TestOmniboxView::SelectAll(bool reversed) {
   if (reversed)
     selection_ = gfx::Range(text_.size(), 0);
@@ -51,9 +72,11 @@
     saved_temporary_selection_ = selection_;
 }
 
-bool TestOmniboxView::OnInlineAutocompleteTextMaybeChanged(
+void TestOmniboxView::OnInlineAutocompleteTextMaybeChanged(
     const base::string16& display_text,
-    size_t user_text_length) {
+    size_t user_text_length,
+    size_t user_text_start,
+    const base::string16& additional_text) {
   const bool text_changed = text_ != display_text;
   text_ = display_text;
   inline_autocomplete_text_ = display_text.substr(user_text_length);
@@ -62,8 +85,6 @@
   // actually changed.
   if (text_changed)
     selection_ = gfx::Range(text_.size(), user_text_length);
-
-  return text_changed;
 }
 
 void TestOmniboxView::OnInlineAutocompleteTextCleared() {
diff --git a/components/omnibox/browser/test_omnibox_view.h b/components/omnibox/browser/test_omnibox_view.h
index 414f1115..3d99175c 100644
--- a/components/omnibox/browser/test_omnibox_view.h
+++ b/components/omnibox/browser/test_omnibox_view.h
@@ -28,6 +28,11 @@
     return inline_autocomplete_text_;
   }
 
+  static State CreateState(std::string text,
+                           size_t sel_start,
+                           size_t sel_end,
+                           size_t all_sel_length);
+
   // OmniboxView:
   void Update() override {}
   void OpenMatch(const AutocompleteMatch& match,
@@ -37,14 +42,17 @@
                  size_t selected_line,
                  base::TimeTicks match_selection_timestamp) override {}
   base::string16 GetText() const override;
-  void SetWindowTextAndCaretPos(const base::string16& text,
-                                size_t caret_pos,
-                                bool update_popup,
-                                bool notify_text_changed) override;
+  void SetWindowTextAndCaretPos(
+      const base::string16& text,
+      size_t caret_pos,
+      bool update_popup,
+      bool notify_text_changed,
+      const base::string16& additional_text = base::string16()) override;
   void SetCaretPos(size_t caret_pos) override {}
   void EnterKeywordModeForDefaultSearchProvider() override {}
   bool IsSelectAll() const override;
   void GetSelectionBounds(size_t* start, size_t* end) const override;
+  size_t GetAllSelectionsLength() const override;
   void SelectAll(bool reversed) override;
   void RevertAll() override {}
   void UpdatePopup() override {}
@@ -54,8 +62,11 @@
                                    const AutocompleteMatch& match,
                                    bool save_original_selection,
                                    bool notify_text_changed) override;
-  bool OnInlineAutocompleteTextMaybeChanged(const base::string16& display_text,
-                                            size_t user_text_length) override;
+  void OnInlineAutocompleteTextMaybeChanged(
+      const base::string16& display_text,
+      size_t user_text_length,
+      size_t user_text_start = 0,
+      const base::string16& additional_text = base::string16()) override;
   void OnInlineAutocompleteTextCleared() override;
   void OnRevertTemporaryText(const base::string16& display_text,
                              const AutocompleteMatch& match) override;
@@ -68,6 +79,7 @@
   void EmphasizeURLComponents() override {}
   void SetEmphasis(bool emphasize, const gfx::Range& range) override {}
   void UpdateSchemeStyle(const gfx::Range& range) override {}
+  using OmniboxView::GetStateChanges;
 
  private:
   base::string16 text_;
diff --git a/components/page_load_metrics/browser/page_load_tracker.cc b/components/page_load_metrics/browser/page_load_tracker.cc
index 1071f7f..e2899eca 100644
--- a/components/page_load_metrics/browser/page_load_tracker.cc
+++ b/components/page_load_metrics/browser/page_load_tracker.cc
@@ -147,9 +147,10 @@
           ->first_paint_after_back_forward_cache_restore !=
       last_timing.back_forward_cache_timing
           ->first_paint_after_back_forward_cache_restore) {
-    DCHECK(!new_timing.back_forward_cache_timing
-                ->first_paint_after_back_forward_cache_restore->is_zero());
-    observer->OnFirstPaintAfterBackForwardCacheRestoreInPage(new_timing);
+    if (new_timing.back_forward_cache_timing
+            ->first_paint_after_back_forward_cache_restore) {
+      observer->OnFirstPaintAfterBackForwardCacheRestoreInPage(new_timing);
+    }
   }
   if (new_timing.paint_timing->first_image_paint &&
       !last_timing.paint_timing->first_image_paint) {
diff --git a/components/paint_preview/common/paint_preview_tracker.cc b/components/paint_preview/common/paint_preview_tracker.cc
index d4d15c7..dede9c03 100644
--- a/components/paint_preview/common/paint_preview_tracker.cc
+++ b/components/paint_preview/common/paint_preview_tracker.cc
@@ -44,14 +44,16 @@
     bool is_main_frame)
     : guid_(guid),
       embedding_token_(embedding_token),
-      is_main_frame_(is_main_frame) {}
+      is_main_frame_(is_main_frame),
+      scroll_(SkISize::Make(0, 0)) {}
 PaintPreviewTracker::~PaintPreviewTracker() = default;
 
 uint32_t PaintPreviewTracker::CreateContentForRemoteFrame(
     const gfx::Rect& rect,
     const base::UnguessableToken& embedding_token) {
   sk_sp<SkPicture> pic = SkPicture::MakePlaceholder(
-      SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()));
+      SkRect::MakeXYWH(rect.x() + scroll_.width(), rect.y() + scroll_.height(),
+                       rect.width(), rect.height()));
   const uint32_t content_id = pic->uniqueID();
   DCHECK(!base::Contains(content_id_to_embedding_token_, content_id));
   content_id_to_embedding_token_[content_id] = embedding_token;
@@ -59,6 +61,10 @@
   return content_id;
 }
 
+void PaintPreviewTracker::SetScrollForFrame(const SkISize& scroll) {
+  scroll_ = scroll;
+}
+
 void PaintPreviewTracker::AddGlyphs(const SkTextBlob* blob) {
   if (!blob)
     return;
diff --git a/components/paint_preview/common/paint_preview_tracker.h b/components/paint_preview/common/paint_preview_tracker.h
index f8993f48..0041603 100644
--- a/components/paint_preview/common/paint_preview_tracker.h
+++ b/components/paint_preview/common/paint_preview_tracker.h
@@ -50,6 +50,9 @@
       const gfx::Rect& rect,
       const base::UnguessableToken& embedding_token);
 
+  // Sets the scroll position for the top layer frame.
+  void SetScrollForFrame(const SkISize& scroll);
+
   // Adds the glyphs in |blob| to the glyph usage tracker for the |blob|'s
   // associated typface.
   void AddGlyphs(const SkTextBlob* blob);
@@ -83,6 +86,8 @@
   const base::Optional<base::UnguessableToken> embedding_token_;
   const bool is_main_frame_;
 
+  SkISize scroll_;
+
   std::vector<mojom::LinkDataPtr> links_;
   PictureSerializationContext content_id_to_embedding_token_;
   TypefaceUsageMap typeface_glyph_usage_;
diff --git a/components/paint_preview/common/paint_preview_tracker_unittest.cc b/components/paint_preview/common/paint_preview_tracker_unittest.cc
index ba050b2..8575ba71 100644
--- a/components/paint_preview/common/paint_preview_tracker_unittest.cc
+++ b/components/paint_preview/common/paint_preview_tracker_unittest.cc
@@ -61,6 +61,33 @@
   // underlying private picture record.
 }
 
+TEST(PaintPreviewTrackerTest, TestRemoteFramePlaceholderPictureWithScroll) {
+  const base::UnguessableToken kDocToken = base::UnguessableToken::Create();
+  const base::UnguessableToken kEmbeddingToken =
+      base::UnguessableToken::Create();
+  PaintPreviewTracker tracker(kDocToken, kEmbeddingToken, true);
+  tracker.SetScrollForFrame(SkISize::Make(10, 20));
+
+  const base::UnguessableToken kEmbeddingTokenChild =
+      base::UnguessableToken::Create();
+  gfx::Rect rect(50, 40, 30, 20);
+  uint32_t content_id =
+      tracker.CreateContentForRemoteFrame(rect, kEmbeddingTokenChild);
+  PictureSerializationContext* context =
+      tracker.GetPictureSerializationContext();
+  EXPECT_TRUE(context->count(content_id));
+  EXPECT_EQ((*context)[content_id], kEmbeddingTokenChild);
+
+  SkPictureRecorder recorder;
+  SkCanvas* canvas = recorder.beginRecording(100, 100);
+  tracker.CustomDataToSkPictureCallback(canvas, content_id);
+  sk_sp<SkPicture> pic = recorder.finishRecordingAsPicture();
+
+  // TODO(crbug/1009552): find a good way to check that a filler picture was
+  // actually inserted into |pic|. This is difficult without using the
+  // underlying private picture record.
+}
+
 TEST(PaintPreviewTrackerTest, TestGlyphRunList) {
   const base::UnguessableToken kEmbeddingToken =
       base::UnguessableToken::Create();
diff --git a/components/paint_preview/renderer/paint_preview_recorder_impl.cc b/components/paint_preview/renderer/paint_preview_recorder_impl.cc
index 7cf5ad87..69e03e76 100644
--- a/components/paint_preview/renderer/paint_preview_recorder_impl.cc
+++ b/components/paint_preview/renderer/paint_preview_recorder_impl.cc
@@ -155,9 +155,12 @@
     bounds = gfx::Rect(params->clip_rect.size());
   }
 
-  cc::PaintRecorder recorder;
   auto tracker = std::make_unique<PaintPreviewTracker>(
       params->guid, frame->GetEmbeddingToken(), is_main_frame_);
+  auto size = frame->GetScrollOffset();
+  tracker->SetScrollForFrame(SkISize::Make(size.width, size.height));
+
+  cc::PaintRecorder recorder;
   cc::PaintCanvas* canvas =
       recorder.beginRecording(bounds.width(), bounds.height());
   canvas->SetPaintPreviewTracker(tracker.get());
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc
index 66ad080..73c22b2 100644
--- a/components/password_manager/core/browser/login_database.cc
+++ b/components/password_manager/core/browser/login_database.cc
@@ -1876,6 +1876,8 @@
   TRACE_EVENT0("passwords", "LoginDatabase::HasUnsyncedDeletions");
 
   std::unique_ptr<syncer::MetadataBatch> batch = GetAllSyncEntityMetadata();
+  if (!batch)
+    return false;
   for (const auto& metadata_entry : batch->GetAllMetadata()) {
     // Note: No need for an explicit "is unsynced" check: Once the deletion is
     // committed, the metadata entry is removed.
@@ -2029,20 +2031,10 @@
       count_removed_logins++;
     }
   }
-
-  if (count_removed_logins > 0) {
-    UMA_HISTOGRAM_COUNTS_100("PasswordManager.RemovedCorruptedPasswords",
-                             count_removed_logins);
-  }
-
-  if (count_removed_logins != forms_to_be_deleted.size()) {
-    metrics_util::LogDeleteCorruptedPasswordsResult(
-        metrics_util::DeleteCorruptedPasswordsResult::kItemFailure);
-  } else if (count_removed_logins > 0) {
+  if (count_removed_logins == forms_to_be_deleted.size() &&
+      count_removed_logins > 0) {
     DCHECK(password_recovery_util_);
     password_recovery_util_->RecordPasswordRecovery();
-    metrics_util::LogDeleteCorruptedPasswordsResult(
-        metrics_util::DeleteCorruptedPasswordsResult::kSuccessPasswordsDeleted);
   }
 #endif
 
diff --git a/components/password_manager/core/browser/login_database_unittest.cc b/components/password_manager/core/browser/login_database_unittest.cc
index c3443da..d2c03d2 100644
--- a/components/password_manager/core/browser/login_database_unittest.cc
+++ b/components/password_manager/core/browser/login_database_unittest.cc
@@ -2454,7 +2454,6 @@
 
 #if defined(OS_MACOSX) && !defined(OS_IOS)
 TEST_F(LoginDatabaseUndecryptableLoginsTest, PasswordRecoveryEnabledGetLogins) {
-  base::HistogramTester histogram_tester;
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(features::kDeleteCorruptedPasswords);
 
@@ -2476,18 +2475,10 @@
 
   RunUntilIdle();
   EXPECT_TRUE(testing_local_state().HasPrefPath(prefs::kPasswordRecovery));
-
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.RemovedCorruptedPasswords", 1, 1);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.DeleteCorruptedPasswordsResult",
-      metrics_util::DeleteCorruptedPasswordsResult::kSuccessPasswordsDeleted,
-      1);
 }
 
 TEST_F(LoginDatabaseUndecryptableLoginsTest,
        PasswordRecoveryDisabledGetLogins) {
-  base::HistogramTester histogram_tester;
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(
       features::kDeleteCorruptedPasswords);
@@ -2509,19 +2500,10 @@
 
   RunUntilIdle();
   EXPECT_FALSE(testing_local_state().HasPrefPath(prefs::kPasswordRecovery));
-
-  EXPECT_TRUE(histogram_tester
-                  .GetAllSamples("PasswordManager.RemovedCorruptedPasswords")
-                  .empty());
-  EXPECT_TRUE(
-      histogram_tester
-          .GetAllSamples("PasswordManager.DeleteCorruptedPasswordsResult")
-          .empty());
 }
 
 TEST_F(LoginDatabaseUndecryptableLoginsTest,
        PasswordRecoveryEnabledKeychainLocked) {
-  base::HistogramTester histogram_tester;
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(features::kDeleteCorruptedPasswords);
 
@@ -2545,14 +2527,6 @@
   RunUntilIdle();
   EXPECT_FALSE(testing_local_state().HasPrefPath(prefs::kPasswordRecovery));
 
-  EXPECT_TRUE(histogram_tester
-                  .GetAllSamples("PasswordManager.RemovedCorruptedPasswords")
-                  .empty());
-  EXPECT_TRUE(
-      histogram_tester
-          .GetAllSamples("PasswordManager.DeleteCorruptedPasswordsResult")
-          .empty());
-
   // Note: it's not possible that encryption suddenly becomes available. This is
   // only used to check that the form is not removed from the database.
   OSCryptMocker::SetBackendLocked(false);
diff --git a/components/password_manager/core/browser/password_autofill_manager.cc b/components/password_manager/core/browser/password_autofill_manager.cc
index 7d54475..6f3d3636 100644
--- a/components/password_manager/core/browser/password_autofill_manager.cc
+++ b/components/password_manager/core/browser/password_autofill_manager.cc
@@ -738,8 +738,8 @@
     }
     return;
   }
-  UpdatePopup(SetUnlockLoadingState(autofill_client_->GetPopupSuggestions(),
-                                    unlock_item, IsLoading(false)));
+  UpdatePopup(SetUnlockLoadingState(reopen_args.suggestions, unlock_item,
+                                    IsLoading(false)));
 }
 
 }  //  namespace password_manager
diff --git a/components/password_manager/core/browser/password_autofill_manager_unittest.cc b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
index 065dd30..03fb1c70 100644
--- a/components/password_manager/core/browser/password_autofill_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -227,6 +227,18 @@
   return suggestions;
 }
 
+autofill::AutofillClient::PopupOpenArgs CreateReopenArgsWithTestSuggestions(
+    bool has_opt_in_and_fill,
+    bool has_opt_in_and_generate,
+    bool has_re_signin) {
+  return {
+      gfx::RectF(), base::i18n::LEFT_TO_RIGHT,
+      CreateTestSuggestions(has_opt_in_and_fill, has_opt_in_and_generate,
+                            has_re_signin),
+      autofill::AutofillClient::PopupOpenArgs::AutoselectFirstSuggestion(false),
+      autofill::PopupType::kPasswords};
+}
+
 }  // namespace
 
 class PasswordAutofillManagerTest : public testing::Test {
@@ -622,11 +634,10 @@
   // As soon as the waiting state is pending, the next update resets the popup.
   EXPECT_CALL(autofill_client, UpdatePopup).WillOnce([&] {
     testing::Mock::VerifyAndClear(&autofill_client);
-    EXPECT_CALL(autofill_client, GetPopupSuggestions)
-        .WillOnce(Return(CreateTestSuggestions(
+    EXPECT_CALL(autofill_client, GetReopenPopupArgs)
+        .WillOnce(Return(CreateReopenArgsWithTestSuggestions(
             /*has_opt_in_and_fill=*/true, /*has_opt_in_and_generate*/ false,
             /*has_re_signin=*/false)));
-    EXPECT_CALL(autofill_client, GetReopenPopupArgs);
     EXPECT_CALL(client, TriggerReauthForPrimaryAccount)
         .WillOnce([](auto reauth_callback) {
           std::move(reauth_callback).Run(ReauthSucceeded(false));
@@ -670,11 +681,10 @@
   // As soon as the waiting state is pending, the next update resets the popup.
   EXPECT_CALL(autofill_client, UpdatePopup).WillOnce([&] {
     testing::Mock::VerifyAndClear(&autofill_client);
-    EXPECT_CALL(autofill_client, GetPopupSuggestions)
-        .WillOnce(Return(CreateTestSuggestions(/*has_opt_in_and_fill=*/false,
-                                               /*has_opt_in_and_generate*/ true,
-                                               /*has_re_signin=*/false)));
-    EXPECT_CALL(autofill_client, GetReopenPopupArgs);
+    EXPECT_CALL(autofill_client, GetReopenPopupArgs)
+        .WillOnce(Return(CreateReopenArgsWithTestSuggestions(
+            /*has_opt_in_and_fill=*/false, /*has_opt_in_and_generate*/ true,
+            /*has_re_signin=*/false)));
     EXPECT_CALL(client, TriggerReauthForPrimaryAccount)
         .WillOnce([](auto reauth_callback) {
           std::move(reauth_callback).Run(ReauthSucceeded(false));
@@ -715,7 +725,10 @@
                                              /*has_opt_in_and_generate*/ false,
                                              /*has_re_signin=*/false)));
   EXPECT_CALL(autofill_client, UpdatePopup);
-  EXPECT_CALL(autofill_client, GetReopenPopupArgs);
+  EXPECT_CALL(autofill_client, GetReopenPopupArgs)
+      .WillOnce(Return(CreateReopenArgsWithTestSuggestions(
+          /*has_opt_in_and_fill=*/true, /*has_opt_in_and_generate*/ false,
+          /*has_re_signin=*/false)));
   EXPECT_CALL(client, TriggerReauthForPrimaryAccount)
       .WillOnce([](auto reauth_callback) {
         std::move(reauth_callback).Run(ReauthSucceeded(true));
@@ -744,7 +757,10 @@
                                              /*has_opt_in_and_generate*/ true,
                                              /*has_re_signin=*/false)));
   EXPECT_CALL(autofill_client, UpdatePopup);
-  EXPECT_CALL(autofill_client, GetReopenPopupArgs);
+  EXPECT_CALL(autofill_client, GetReopenPopupArgs)
+      .WillOnce(Return(CreateReopenArgsWithTestSuggestions(
+          /*has_opt_in_and_fill=*/false, /*has_opt_in_and_generate*/ true,
+          /*has_re_signin=*/false)));
   EXPECT_CALL(client, TriggerReauthForPrimaryAccount)
       .WillOnce([](auto reauth_callback) {
         std::move(reauth_callback).Run(ReauthSucceeded(true));
diff --git a/components/password_manager/core/browser/password_manager_metrics_util.cc b/components/password_manager/core/browser/password_manager_metrics_util.cc
index b38efc6..4d1591c9 100644
--- a/components/password_manager/core/browser/password_manager_metrics_util.cc
+++ b/components/password_manager/core/browser/password_manager_metrics_util.cc
@@ -231,11 +231,6 @@
       "PasswordManager.DeleteUndecryptableLoginsReturnValue", result);
 }
 
-void LogDeleteCorruptedPasswordsResult(DeleteCorruptedPasswordsResult result) {
-  base::UmaHistogramEnumeration(
-      "PasswordManager.DeleteCorruptedPasswordsResult", result);
-}
-
 void LogNewlySavedPasswordIsGenerated(
     bool value,
     PasswordAccountStorageUsageLevel account_storage_usage_level) {
diff --git a/components/password_manager/core/browser/password_manager_metrics_util.h b/components/password_manager/core/browser/password_manager_metrics_util.h
index 3dc2839..c468739d 100644
--- a/components/password_manager/core/browser/password_manager_metrics_util.h
+++ b/components/password_manager/core/browser/password_manager_metrics_util.h
@@ -510,10 +510,6 @@
 void LogDeleteUndecryptableLoginsReturnValue(
     DeleteCorruptedPasswordsResult result);
 
-// Log a result of removing passwords that couldn't be decrypted with the
-// present encryption key on MacOS.
-void LogDeleteCorruptedPasswordsResult(DeleteCorruptedPasswordsResult result);
-
 // Log whether a saved password was generated.
 void LogNewlySavedPasswordIsGenerated(
     bool value,
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 69ca89a..4d6392a1 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -4666,7 +4666,7 @@
       'id': 443,
       'caption': '''Control where Developer Tools can be used''',
       'tags': [],
-      'desc': '''Setting the policy to 0 (the default) means you can access the developer tools and the JavaScript console, but not in the context of extensions installed by enterprise policy. Setting the policy to 1 means you can access the developer tools and the JavaScript console in all contexts, including that of extensions installed by enterprise policy. Setting the policy to 2 developer tools means you can't acess developer tools, and you can't inspect website elements.
+      'desc': '''Setting the policy to 0 (the default) means you can access the developer tools and the JavaScript console, but not in the context of extensions installed by enterprise policy. Setting the policy to 1 means you can access the developer tools and the JavaScript console in all contexts, including that of extensions installed by enterprise policy. Setting the policy to 2 means you can't acess developer tools, and you can't inspect website elements.
 
       This setting also turns off keyboard shortcuts and menu or context menu entries to open developer tools or the JavaScript console.''',
       'arc_support': '''This policy also controls access to Android Developer Options. If you set this policy to 'DeveloperToolsDisallowed' (value 2), users cannot access Developer Options. If you set this policy to another value or leave it unset, users can access Developer Options by tapping seven times on the build number in the Android settings app.''',
@@ -16455,7 +16455,8 @@
           'caption': '''Authentication based on client certificates''',
         },
       ],
-      'future_on': ['chrome_os'],
+      'supported_on':[],
+      'future': True,
       'device_only': True,
       'features': {
         'dynamic_refresh': True,
@@ -18093,6 +18094,26 @@
       The policy should be specified as a string that expresses the URL and hash in the JSON format.''',
     },
     {
+      'name': 'PluginVmDataCollectionAllowed',
+      'owners': ['okalitova@chromium.org', 'janagrill@chromium.org'],
+      'type': 'main',
+      'schema': { 'type': 'boolean' },
+      'supported_on': ['chrome_os:85-'],
+      'features': {
+        'dynamic_refresh': True,
+        'per_profile': False,
+      },
+      'future': True,
+      'example_value': False,
+      'id': 712,
+      'caption': '''Allow <ph name="PLUGIN_VM_NAME">PluginVm</ph> Product Analytics''',
+      'tags': [],
+      'desc': '''Allow <ph name="PLUGIN_VM_NAME">PluginVm</ph> to collect <ph name="PLUGIN_VM_NAME">PluginVm</ph> usage data.
+
+      If the policy is set to false or left unset, <ph name="PLUGIN_VM_NAME">PluginVm</ph> is not allowed to collect data.
+      If set to true, <ph name="PLUGIN_VM_NAME">PluginVm</ph> might collect <ph name="PLUGIN_VM_NAME">PluginVm</ph> usage data that is then combined and thoroughly analyzed to improve <ph name="PLUGIN_VM_NAME">PluginVm</ph> experience.''',
+    },
+    {
       'name': 'ParentAccessCodeConfig',
       'owners': ['file://src/chrome/browser/chromeos/child_accounts/OWNERS'],
       'type': 'dict',
@@ -22002,10 +22023,11 @@
       'caption': '''PluginVm''',
       'policies': [
         'PluginVmAllowed',
-        'UserPluginVmAllowed',
+        'PluginVmDataCollectionAllowed',
         'PluginVmLicenseKey',
         'PluginVmImage',
         'PluginVmUserId',
+        'UserPluginVmAllowed',
       ],
     },
     {
@@ -22124,6 +22146,6 @@
   ],
   'placeholders': [],
   'deleted_policy_ids': [412, 476, 546, 562, 569, 578],
-  'highest_id_currently_used': 711,
+  'highest_id_currently_used': 712,
   'highest_atomic_group_id_currently_used': 38
 }
diff --git a/components/policy/resources/policy_templates_de.xtb b/components/policy/resources/policy_templates_de.xtb
index 1b97d82f..c78bb99 100644
--- a/components/policy/resources/policy_templates_de.xtb
+++ b/components/policy/resources/policy_templates_de.xtb
@@ -4821,7 +4821,7 @@
       Falls die Richtlinie "DeviceIdleLogoutTimeout" konfiguriert ist, wird mithilfe der vorliegenden Richtlinie festgelegt, wie lange das Warnfenster mit Countdown für Nutzer zu sehen sein soll, bevor sie abgemeldet werden.
 
       Der Wert für die Richtlinie sollte in Millisekunden angegeben werden.</translation>
-<translation id="8331479227794770304">Sticky Keys aktivieren</translation>
+<translation id="8331479227794770304">Einfingerbedienung aktivieren</translation>
 <translation id="8339420913453596618">Zweiter Authentifizierungsfaktor deaktiviert</translation>
 <translation id="8344454543174932833">Lesezeichen bei erster Ausführung aus Standardbrowser importieren</translation>
 <translation id="8347993687936322631">Diese Richtlinie ist veraltet und wird in Version 85 von <ph name="PRODUCT_OS_NAME" /> entfernt. Bitte verwenden Sie stattdessen die Richtlinie "<ph name="POWER_MANAGEMENT_IDLE_SETTINGS_POLICY_NAME" />".
diff --git a/components/policy/resources/policy_templates_es-419.xtb b/components/policy/resources/policy_templates_es-419.xtb
index a3d6c2f7..3783d20 100644
--- a/components/policy/resources/policy_templates_es-419.xtb
+++ b/components/policy/resources/policy_templates_es-419.xtb
@@ -352,6 +352,9 @@
 <translation id="1583248206450240930">Utilizar <ph name="PRODUCT_FRAME_NAME" /> de manera predeterminada</translation>
 <translation id="1588240398285670601">Configuración del navegador</translation>
 <translation id="1599424828227887013">Habilitar el aislamiento de sitios para orígenes específicos en dispositivos Android</translation>
+<translation id="159946228300522107">Si estableces la política como verdadera, Chrome maximizará la primera ventana que se muestre en la primera ejecución.
+
+      Si la estableces como falsa o no la estableces, Chrome maximizará la primera ventana siempre que el tamaño de la pantalla lo permita.</translation>
 <translation id="1608755754295374538">Las URL que recibirán acceso a dispositivos de captura de audio sin solicitarlo</translation>
 <translation id="1615221548356595305">Permitir la integración de conexiones HTTP/2 para estos hosts incluso cuando se usan certificados de cliente</translation>
 <translation id="1615855314789673708">Proporciona una configuración del DTC (controlador de telemetría y diagnósticos) wilco.
@@ -411,6 +414,9 @@
         Agrega expresiones regulares de URL a |url_list| para incluir en la lista blanca URL que coincidan con cualquier expresión regular de la lista.
         Para incluir una app en la lista blanca, agrégala con sus valores de |app_id| y |app_type| a |app_list|.
        </translation>
+<translation id="171511968762040550">Si la estableces esta política como verdadera o no la estableces, los usuarios podrán agregar, quitar o modificar favoritos.
+
+      Si la estableces como falsa, los usuarios no podrán agregar, quitar ni modificar favoritos, pero podrán seguir utilizando los existentes.</translation>
 <translation id="1715151459541210849">Habilita la función de accesibilidad de dictado</translation>
 <translation id="1717817358640580294">Si no se establece, en caso de que "Limpiar Chrome" detecte software no deseado, es posible que informe metadatos sobre el análisis a Google en conformidad con la política establecida por SafeBrowsingExtendedReportingEnabled. Además, "Limpiar Chrome" le preguntará al usuario si quiere borrar el software no deseado y si desea compartir los resultados de la limpieza con Google a fin de colaborar con futuras detecciones de ese tipo de software. Estos resultados contienen metadatos de archivos, extensiones instaladas automáticamente y claves de registro, como se describe en el Informe de privacidad de Chrome.
 
@@ -765,6 +771,12 @@
 <translation id="2214880135980649323">Si se habilita esta política, las extensiones que instale una política empresarial podrán usar la API de plataforma de hardware empresarial.
       Si se establece esta política como inhabilitada, o no se configura, las extensiones no podrán usar la API de plataforma de hardware empresarial.
       Esta política también se aplica en las extensiones de componentes, como la extensión de Servicios de Hangout.</translation>
+<translation id="2215238871726750562">Si estableces la política como verdadera, no se ejecutará la ventana del navegador al inicio de la sesión.
+
+      Si la estableces como falsa o no la estableces, se podrá ejecutar la ventana.
+
+      Nota: Es posible que otras políticas o marcas de la línea de comandos impidan la ejecución de la ventana del navegador.</translation>
+<translation id="2223582957891074498">Si estableces la política como verdadera, no se permitirá realizar capturas de pantalla con combinaciones de teclas o API de extensiones. Si la estableces como falsa, se permitirá realizar capturas de pantalla.</translation>
 <translation id="2223598546285729819">Configuración de notificación predeterminada</translation>
 <translation id="2231817271680715693">Importar historial de navegación del navegador predeterminado en la primera ejecución</translation>
 <translation id="2236488539271255289">No permitir que ningún sitio configure los datos locales.</translation>
@@ -797,6 +809,9 @@
 
       Si esta opción no se configura, los usuarios pueden elegir utilizar o no el servicio de revisión ortográfica.</translation>
 <translation id="229322770310505679">Habilita el concepto de grupos atómicos de políticas</translation>
+<translation id="22941467117331786">Si estableces la política como verdadera, se mostrará un botón grande y rojo para salir de la cuenta. Lo encontrarás en la bandeja del sistema durante sesiones activas y con la pantalla desbloqueada.
+
+      Si la estableces como falsa o no la estableces, no se mostrará ningún botón.</translation>
 <translation id="2294382669900758280">No se tiene en cuenta la reproducción de video en las apps de Android, incluso si esta política se establece como <ph name="TRUE" />.</translation>
 <translation id="2299220924812062390">Especificar una lista de complementos habilitados</translation>
 <translation id="2303795211377219696">Habilitar la función Autocompletar para tarjetas de crédito</translation>
@@ -1331,7 +1346,7 @@
 <translation id="299519952839316970">Ten en cuenta que esta política es obsoleta y se quitará en la versión 88 de <ph name="PRODUCT_OS_NAME" />. Ya no se admiten las sesiones públicas. En su lugar, utiliza <ph name="DEVICE_LOCAL_ACCOUNTS_POLICY_NAME" /> para configurar las sesiones de invitado administradas.
       Si estableces esta política como falsa, las sesiones de invitado administradas se comportarán como se indica en https://support.google.com/chrome/a/answer/3017014, la "sesión pública" estándar.
 
-      Si la estableces como verdadera o no la estableces, las sesiones de invitado administradas se comportarán como "sesiones administradas", las cuales no incluyen muchas de las restricciones que se aplican a las "sesiones públicas" estándar.
+      Si la estableces como verdadera o no la estableces, las sesiones de invitado administradas se comportarán como "sesiones administradas" y no incluirán muchas de las restricciones que se aplican a las "sesiones públicas" estándar.
 
       Si la estableces, el usuario no podrá cambiarla ni anularla.</translation>
 <translation id="3016255526521614822">Incluir en la lista blanca las apps para tomar notas que se permiten en la pantalla bloqueada de <ph name="PRODUCT_OS_NAME" /></translation>
@@ -1394,7 +1409,7 @@
 
         Es posible que una política experimental no esté terminada o tenga defectos conocidos o desconocidos. Esta política puede modificarse o quitarse sin previo aviso. Si habilitas las políticas experimentales, podrías perder datos de navegación o poner en riesgo tu seguridad o privacidad.
 
-        Si una política no se encuentra en la lista y no se publicó oficialmente, se ignorará su valor en las versiones beta y estable de Chrome.
+        Si una política no se encuentra en la lista y no se publicó oficialmente, se ignorará su valor en las versiones Beta y estable de Chrome.
 
         Si una política se encuentra en la lista, pero no se publicó oficialmente, se aplicará su valor.
 
@@ -1940,9 +1955,9 @@
 
           Si la política no se establece o se establece en false, los usuarios podrán transferir archivos a Google Drive.</translation>
 <translation id="3915395663995367577">URL a un archivo proxy .pac</translation>
-<translation id="3917288538553140422">Si estableces la política, se especificará la acción que debe realizarse cuando se creó el directorio principal del usuario con la encriptación ecryptfs. A menos que los directorios principales con la encriptación ecryptfs migren a la encriptación ext4, es posible que las apps de Android dejen de funcionar.
+<translation id="3917288538553140422">Si estableces la política, se especificará la acción que debe realizarse si el directorio principal del usuario se creó con la encriptación ecryptfs. A menos que los directorios principales con la encriptación ecryptfs migren a la encriptación ext4, es posible que las apps de Android dejen de funcionar.
 
-      Si estableces la política en los siguientes valores:
+      Si estableces la política en:
 
       * "Migrate" (o una opción no compatible como AskUser o AskForEcryptfsArcUsers): Los directorios migrarán automáticamente a la encriptación ext4 cuando el usuario acceda, sin solicitarle permiso.
 
@@ -2469,6 +2484,9 @@
 <translation id="4802905909524200151">Configurar el comportamiento de actualización del firmware <ph name="TPM_FIRMWARE_UPDATE_TPM" /></translation>
 <translation id="4804828344300125154">Reinicia siempre cuando el usuario sale de su cuenta.</translation>
 <translation id="4807950475297505572">Elimina los usuarios que más tiempo hace que no se utilizan hasta que se libere espacio suficiente.</translation>
+<translation id="4812270373673968774">Si estableces la política como "Always", se ocultará la biblioteca de <ph name="PRODUCT_OS_NAME" /> de forma automática. Si la estableces como "Never", no se ocultará nunca la biblioteca de forma automática.
+
+      Si estableces la política, los usuarios no podrán cambiarla. Si no la estableces, los usuarios podrán decidir si se oculta la biblioteca de forma automática.</translation>
 <translation id="4816674326202173458">Permitir que el usuario de empresa sea principal y secundario (comportamiento predeterminado para usuarios no administrados)</translation>
 <translation id="4826326557828204741">Acción a realizar si se alcanza la demora de inactividad mientras el dispositivo funciona con batería</translation>
 <translation id="4830531683854509779">Envía informes sobre las estadísticas de hardware para los componentes de SoC.
@@ -2548,6 +2566,9 @@
 <translation id="4986560318567565414">Ruta a Chrome para el cambio desde el navegador alternativo</translation>
 <translation id="4988291787868618635">Acción que se realiza cuando se alcanza la demora de inactividad</translation>
 <translation id="500149597848135831">Habilitar todas las variaciones</translation>
+<translation id="5017369989680827157">Si estableces la política como verdadera o no la estableces, los usuarios podrán configurar la función Autocompletar para las direcciones que aparecen en la IU.
+
+      Si la estableces como falsa, la función Autocompletar nunca sugerirá ni completará datos de las direcciones, ni guardará información adicional relacionada que envíen los usuarios cuando navegan por la Web.</translation>
 <translation id="5023555740504506178">Si se habilita o no se configura (predeterminado), una página web podrá utilizar
       las API para compartir pantalla (p. ej., getDisplayMedia() o la API de la extensión Captura del escritorio)
       para solicitarle al usuario que seleccione una pestaña, una ventana o un escritorio para capturar.
@@ -2590,6 +2611,9 @@
 <translation id="5073609397321802133">Si se establece la política como falsa, los usuarios no podrán personalizar el fondo en la página Nueva pestaña. En caso de que haya un fondo personalizado, este se quitará de forma permanente, incluso si más tarde se establece la política como verdadera.
 
       Si se establece la política como verdadera o no se establece, los usuarios podrán personalizar el fondo en la página Nueva pestaña.</translation>
+<translation id="5075190314377370852">Si estableces la política como verdadera, <ph name="PRODUCT_NAME" /> siempre comprobará la revocación de los certificados del servidor validados correctamente y firmados por certificados de CA instalados de manera local. Si <ph name="PRODUCT_NAME" /> no puede obtener información del estado de revocación, <ph name="PRODUCT_NAME" /> considerará estos certificados como revocados (rechazados).
+
+      Si estableces la política como falsa o no la estableces, <ph name="PRODUCT_NAME" /> utilizará la configuración para comprobar la revocación en línea actual.</translation>
 <translation id="5075834892754086022">Si se configura la política, se aplicará la extensión mínima de PIN configurada. (El valor absoluto de la extensión mínima del PIN es 1; los valores menores que 1 se considerarán como 1).
 
           Si no se configura la política, se aplicará una extensión mínima del PIN de 6 dígitos. Esta es la extensión mínima recomendada.</translation>
@@ -2655,6 +2679,11 @@
       mínimo es 30 segundos y el máximo es 24 horas; los
       valores fuera de estos límites se establecerán dentro del rango.</translation>
 <translation id="5163002264923337812">Habilitar la forma de acceso antigua basada en la Web</translation>
+<translation id="516520353995300280">Si estableces la política, la cual inhabilita la aplicación de los requisitos de divulgación del Certificado de transparencia para una lista de autoridades certificadas (CA) heredadas, se inhabilitarán estos requisitos para las cadenas que contengan certificados con uno de los hash de <ph name="SUBJECT_PUBLIC_KEY_INFO" /> especificados. Los hosts empresariales podrán seguir usando los certificados que no sean de confianza (porque no se divulgaron públicamente de forma correcta). Para inhabilitar la aplicación, los hash de <ph name="SUBJECT_PUBLIC_KEY_INFO" /> deben aparecer en un certificado de CA reconocido como CA heredada. Una CA heredada es una CA que cuenta con la confianza pública de uno o más sistemas operativos compatibles con <ph name="PRODUCT_NAME" />, pero no son de confianza para el Proyecto de código abierto de Android o <ph name="PRODUCT_OS_NAME" />.
+
+      Para especificar un hash de <ph name="SUBJECT_PUBLIC_KEY_INFO" />, se debe vincular el nombre del algoritmo del hash, una barra y la codificación de Base64 de ese algoritmo aplicada al campo <ph name="SUBJECT_PUBLIC_KEY_INFO" /> codificado con DER del certificado específico. Esta codificación de Base64 tiene el mismo formato que una SPKI Fingerprint. El único algoritmo de hash compatible es sha256; se ignorarán los demás.
+
+      Si no estableces esta política, <ph name="PRODUCT_NAME" /> considerará que no son de confianza los certificados que no se divulguen, a pesar de requerir divulgación mediante el Certificado de transparencia.</translation>
 <translation id="5168529971295111207">Esta política es obsoleta. Usa la política ProxyMode en su lugar.
 
           Te permite especificar el servidor proxy que utiliza <ph name="PRODUCT_NAME" /> y evita que los usuarios cambien la configuración del proxy.
@@ -2798,6 +2827,9 @@
 
       Si la política no se establece, se establece con un intervalo de puertos no válido o se deja como una cadena vacía, WebRTC puede usar cualquier puerto UDP local disponible.</translation>
 <translation id="5290940294294002042">Especificar una lista de complementos que el usuario puede habilitar o inhabilitar.</translation>
+<translation id="5293044154216294358">Si estableces la política como verdadera, los usuarios podrán jugar al juego del dinosaurio. Si estableces la política como falsa, los usuarios no podrán jugar al juego del huevo de pascua del dinosaurio cuando el dispositivo esté sin conexión.
+
+      Si no la estableces, los usuario no podrán jugar al juego en el <ph name="PRODUCT_OS_NAME" /> registrado, pero podrán hacerlo en otras circunstancias.</translation>
 <translation id="5306186200045823863">Habilitar la confianza en la infraestructura de PKI heredada de Symantec Corporation</translation>
 <translation id="5307432759655324440">Disponibilidad del modo incógnito</translation>
 <translation id="5311275381462687162">Configuración predeterminada del atributo heredado <ph name="ATTRIBUTE_SAMESITE_NAME" /> para el comportamiento de las cookies</translation>
@@ -2956,7 +2988,7 @@
 
       Se planea quitar esta política en la versión <ph name="PRODUCT_NAME" /> 87 para Mac OS, cuando se quite la compatibilidad con el verificador de certificados heredado de Mac OS X.
       </translation>
-<translation id="5494917047563607689">Si se establece en menos de 1 MB o no se establece, el <ph name="PRODUCT_OS_NAME" /> usará el tamaño predeterminado para almacenar en caché las apps y extensiones cuando las instalan varios usuarios del mismo dispositivo. Esta acción evitará que cada usuario las tenga que volver a descargar.</translation>
+<translation id="5494917047563607689">Si se establece en menos de 1 MB o no se establece, <ph name="PRODUCT_OS_NAME" /> usará el tamaño predeterminado para almacenar en caché las apps y extensiones cuando las instalan varios usuarios del mismo dispositivo. Esta acción evitará que cada usuario las tenga que volver a descargar.</translation>
 <translation id="5498045818698736356">Especifica una lista de aplicaciones web que se instalan de manera silenciosa, sin interacción del usuario y que este no puede desinstalar ni inhabilitar.
 
       Cada elemento de la lista de la política es un objeto con un miembro obligatorio "url" y dos miembros opcionales: "default_launch_container" y "create_desktop_shortcut". "url" debe ser la URL de la aplicación web que se va a instalar, "launch_container" debe ser "window" o "tab" para indicar cómo se abrirá la app una vez que se instale, y "create_desktop_shortcut" debe ser verdadero para crear un acceso directo de escritorio en Linux y Windows. Si se omite "default_launch_container", se abrirá la app en una pestaña de forma predeterminada. Más allá del valor de "default_launch_container", los usuarios podrán cambiar el contenedor donde se abrirá la app. Si se omite "create_desktop_shortcuts", no se crearán accesos directos de escritorio. Consulta la política <ph name="PINNED_LAUNCHER_APPS_POLICY_NAME" /> para fijar apps a la biblioteca de ChromeOS.</translation>
@@ -3073,6 +3105,9 @@
 
       NOTA: Esta política se aplica solo a las versiones de Chrome para Android que se ejecuten en dispositivos únicamente con más de 1 GB de RAM. Para aplicar la política en plataformas que no sean Android, utiliza IsolateOrigins.
       </translation>
+<translation id="5595998409088126162">Si estableces la política, se definirá una lista de favoritos en la que cada uno es un diccionario que contiene las claves "<ph name="NAME" />" y "<ph name="URL_LABEL" />" con el nombre y objetivo del favorito. Los administradores pueden configurar una subcarpeta definiendo un favorito sin una clave "<ph name="URL_LABEL" />", pero con una clave "<ph name="CHILDREN" />" adicional que contenga una lista de favoritos (algunos pueden ser carpetas). Chrome modifica las URL incompletas como si fueran enviadas a través de la barra de direcciones, p. ej., "<ph name="GOOGLE_COM" />" cambia a "<ph name="HTTPS_GOOGLE_COM" />".
+
+      Los usuarios no podrán modificar las carpetas donde se guardan los favoritos (pero podrán ocultarlas en la barra de favoritos). El nombre de la carpeta es "Favoritos administrados", pero los usuarios podrán agregar a la lista de favoritos un diccionario que incluya la clave "<ph name="TOPLEVEL_NAME" />" con el nombre deseado de la carpeta como valor. Los favoritos administrados no se sincronizarán con la cuenta del usuario y no se podrán modificar mediante extensiones.</translation>
 <translation id="5599461642204007579">Configuración de la administración de <ph name="MS_AD_NAME" /></translation>
 <translation id="5618398258385745432">La configuración asociada se usó antes de implementar la reautenticación para ver contraseñas. A partir de ese momento, la configuración y, por lo tanto, esta política no tienen efecto en el comportamiento de Chrome. El comportamiento actual de Chrome es como si la política se hubiera establecido para no ver las contraseñas en texto claro en las páginas de configuración del administrador de contraseñas. Esto significa que la página de configuración contiene solo un marcador de posición y Chrome mostrará la contraseña después de que el usuario haga clic en "Mostrar" (e implemente la reautenticación, si corresponde). A continuación, se muestra la descripción original de la política.
 
@@ -3111,6 +3146,9 @@
       Si se establece en 0, se desactiva el almacenamiento en caché de los datos de autenticación. Esta acción puede ralentizar significativamente el acceso de los usuarios afiliados, dado que deben obtenerse los datos específicos del dominio en cada acceso.
 
       Ten en cuenta que se almacenan en caché incluso los datos de dominio de usuarios ocasionales. Si no quieres registrar el dominio de usuarios ocasionales, desactiva el almacenamiento en caché.</translation>
+<translation id="5700097087679928356">Si estableces la política con el valor "0" (la opción predeterminada), podrás acceder a las herramientas para desarrolladores y la Consola de JavaScript, pero no podrás hacerlo en el contexto de extensiones instaladas por una política empresarial. Si estableces la política con el valor "1", podrás acceder a las herramientas para desarrolladores y la Consola de JavaScript en todos los contextos, incluido el de las extensiones instaladas por una política empresarial. Si estableces la política con el valor "2", no podrás acceder a las herramientas para desarrolladores ni inspeccionar elementos de sitios web.
+
+      Esta configuración también desactivará las combinaciones de teclas y las entradas del menú contextual o de cualquier menú.</translation>
 <translation id="570062449808736508">Cuando esta política se establece con una string no vacía, WebView leerá las restricciones de URL del proveedor de contenido con el nombre de la autoridad proporcionado.</translation>
 <translation id="5708969689202733975">Configurar los modos de desbloqueo rápido permitidos</translation>
 <translation id="5711016543513883877">
@@ -3335,9 +3373,9 @@
 
       Si se le asigna el valor "Bloquear las cargas y descargas grandes", <ph name="PRODUCT_NAME" /> se comportará conforme a las reglas descritas en "Bloquear descargas grandes" y "Bloquear cargas grandes".
       </translation>
-<translation id="6082161804984853051">Si estableces la política, <ph name="PRODUCT_NAME" /> utilizará el directorio que proporciones para guardar los archivos almacenados en caché que se encuentren en el disco, independientemente de si los usuarios especifican la marca --disk-cache-dir.
+<translation id="6082161804984853051">Si estableces la política, <ph name="PRODUCT_NAME" /> utilizará el directorio que proporciones para guardar los archivos almacenados en caché que se encuentren en el disco, independientemente de si los usuarios especifican la función experimental --disk-cache-dir.
 
-      Si no la estableces, <ph name="PRODUCT_NAME" /> utilizará el directorio predeterminado para el almacenamiento en caché, pero los usuarios podrán cambiar esa configuración con la marca de la línea de comandos --disk-cache-dir.
+      Si no la estableces, <ph name="PRODUCT_NAME" /> utilizará el directorio predeterminado para el almacenamiento en caché, pero los usuarios podrán cambiar esa configuración con la función experimental de la línea de comandos --disk-cache-dir.
 
       <ph name="PRODUCT_NAME" /> administra el contenido del directorio raíz de un volumen. Por lo tanto, para evitar pérdida de datos u otros errores, no establezcas esta política para el directorio raíz o cualquier directorio que se utilice para otros propósitos. Consulta las variables que puedes utilizar (https://www.chromium.org/administrators/policy-list-3/user-data-directory-variables).</translation>
 <translation id="6083631234867522991">Windows (clientes de Windows):</translation>
@@ -3361,6 +3399,11 @@
 <translation id="6099853574908182288">Modo predeterminado de impresión a color</translation>
 <translation id="6102342563050263313">Habilitar el desplazamiento al texto especificado en fragmentos de URL</translation>
 <translation id="6107642964266628393">Controla cuándo y cómo se aplican las actualizaciones del Sistema operativo Chrome.</translation>
+<translation id="6110478331147706293">Si estableces la política, se desactivarán los requisitos de divulgación del Certificado de transparencia para los nombres de host en las URL especificadas. Si bien esta acción dificulta la detección de los certificados que se usan de forma incorrecta, los hosts pueden seguir usando certificados que no sean de confianza (porque no se divulgaron públicamente de forma correcta).
+
+      Si no estableces esta política, <ph name="PRODUCT_NAME" /> considerará que no son de confianza los certificados que no se divulguen, a pesar de requerir divulgación mediante el Certificado de transparencia.
+
+      El patrón de una URL tiene el siguiente formato (https://www.chromium.org/administrators/url-blacklist-filter-format). Sin embargo, dado que la validez de los certificados para un nombre de host específico no depende del esquema, el puerto ni la ruta, <ph name="PRODUCT_NAME" /> solo considerará la porción de la URL con el nombre de host. Los hosts con comodines no son compatibles.</translation>
 <translation id="6111936128861357925">Permitir juego del huevo de pascua del dinosaurio</translation>
 <translation id="6114416803310251055">en desuso</translation>
 <translation id="6133088669883929098">Permitir que todos los sitios utilicen la generación de claves</translation>
@@ -3406,6 +3449,11 @@
           Para obtener ejemplos detallados, visita:
           <ph name="PROXY_HELP_URL" />.</translation>
 <translation id="6178075938488052838">Esta política controla quién puede iniciar una sesión en <ph name="PRODUCT_OS_NAME" />, pero no impide que los usuarios accedan a otras cuentas de Google en Android. Si quieres impedirlo, configura la política <ph name="ACCOUNT_TYPES_WITH_MANAGEMENT_DISABLED_CLOUDDPC_POLICY_NAME" /> específica de Android como parte de la política <ph name="ARC_POLICY_POLICY_NAME" />.</translation>
+<translation id="6183327369896253878">Si estableces la política, se determinarán los identificadores de apps que el <ph name="PRODUCT_OS_NAME" /> mostrará como apps fijas en la barra del Selector; los usuarios no podrán cambiarlos.
+
+      Especifica las apps de Chrome por ID, como pjkljhegncpnkpknbcohdijeoejaedia; las apps de Android por nombre de paquete, como com.google.android.gm; y las aplicaciones web por la URL utilizada en <ph name="WEB_APP_INSTALL_FORCE_LIST_POLICY_NAME" />, como https://google.com/maps.
+
+      Si no estableces la política, los usuarios podrán cambiar la lista de apps fijas en el Selector.</translation>
 <translation id="6190022522129724693">Configuración predeterminada de ventanas emergentes</translation>
 <translation id="6190367314942602985">Enviar la información de identificación del usuario</translation>
 <translation id="6195802366906945965">Determina si se utilizará el verificador de certificados integrado para verificar los certificados de servidores</translation>
@@ -3525,6 +3573,9 @@
 
       Si configuras esta política, podrás establecer si un usuario tiene permiso para acceder a <ph name="PRODUCT_NAME" />. Si estableces esta política como "False", las apps y extensiones no podrán usar la API de chrome.identity, por lo que probablemente sea conveniente usar "SyncDisabled".</translation>
 <translation id="6378076389057087301">Especificar si la actividad de audio afecta a la administración de energía</translation>
+<translation id="6378393933102834628">Si estableces la política como verdadera, se mostrarán los accesos directos a aplicaciones. Si la estableces como falsa, no se mostrarán nunca los accesos directos.
+
+      Si estableces la política, los usuarios no podrán cambiarla. Si no la estableces, los usuarios podrán ocultar o mostrar los accesos directos a aplicaciones desde el menú contextual de la barra de favoritos.</translation>
 <translation id="637934607141010488">Informa sobre la lista de usuarios de dispositivos que accedieron recientemente.
 
       Si esta política se establece en "False", no se informará sobre los usuarios.</translation>
@@ -3744,6 +3795,17 @@
 <translation id="6689792153960219308">Informar estado de hardware</translation>
 <translation id="6698632841807204978">Habilitar la impresión monocromática</translation>
 <translation id="6699880231565102694">Habilitar autenticación de dos factores para los hosts de acceso remoto.</translation>
+<translation id="6703251016607733593">Si estableces la política, se inhabilitará la aplicación de los requisitos de divulgación del Certificado de transparencia para una lista de hash de <ph name="SUBJECT_PUBLIC_KEY_INFO" />. Los hosts empresariales podrán seguir usando los certificados que no sean de confianza (porque no se divulgaron públicamente de forma correcta). Para inhabilitar la aplicación, el hash debe complir con una de las siguientes condiciones:
+
+      * El hash pertenece al campo <ph name="SUBJECT_PUBLIC_KEY_INFO" /> del certificado del servidor.
+
+      * El hash pertenece a un campo <ph name="SUBJECT_PUBLIC_KEY_INFO" /> que aparece en un certificado de autoridad certificada (CA) en la cadena de certificados; ese certificado de CA está limitado por la extensión X.509v3 nameConstraints; uno o más directoryName nameConstraints están presentes en permittedSubtrees; y directoryName contiene un atributo organizationName.
+
+      * El hash pertenece a un campo <ph name="SUBJECT_PUBLIC_KEY_INFO" /> que aparece en un certificado de CA en la cadena de certificados; ese certificado de CA tiene uno o más atributos organizationName en el asunto del certificado; y el certificado del servidor contiene la misma cantidad de atributos organizationName, en el mismo orden y con los mismos valores, byte por byte.
+
+      Para especificar un hash de <ph name="SUBJECT_PUBLIC_KEY_INFO" />, se debe vincular el nombre del algoritmo del hash, una barra y la codificación de Base64 de ese algoritmo aplicada al campo <ph name="SUBJECT_PUBLIC_KEY_INFO" /> codificado con DER del certificado específico. Esta codificación de Base64 tiene el mismo formato que una SPKI Fingerprint. El único algoritmo de hash compatible es sha256; se ignorarán los demás.
+
+      Si no estableces esta política, <ph name="PRODUCT_NAME" /> considerará que no son de confianza los certificados que no se divulguen, a pesar de requerir divulgación mediante el Certificado de transparencia.</translation>
 <translation id="6704515759227307131">Esta política es obsoleta y se reemplazó por AdvancedProtectionAllowed.
 
       Esta política controla si los usuarios inscritos en el Programa de Protección Avanzada pueden enviar sus descargas a Google para comprobar que no incluyan software malicioso. Si se establece como verdadera o no se establece, se les pedirá a los usuarios inscritos que envíen sus archivos a Google para un análisis en profundidad. Si el usuario selecciona "Analizar", se enviará la descarga a Google. Si se establece como falsa, no se les pedirá a los usuarios que realicen ninguna acción y no se enviarán sus descargas a Google.</translation>
@@ -3754,6 +3816,9 @@
           A partir de <ph name="PRODUCT_NAME" /> 76, la configuración predeterminada se comportará como si estuviera inhabilitada.
 
           A partir de <ph name="PRODUCT_NAME" /> 78, se ignorará esta política y se tratará como inhabilitada.</translation>
+<translation id="672496466524161417">Si estableces la política como "None" o no la estableces, los usuarios podrán administrar los certificados. Si la estableces con el valor "2", los usuarios solo podrán ver los certificados (pero no podrán administrarlos).
+
+      Si la estableces con el valor "1", los usuarios podrán administrar los certificados de usuario, pero no los de todo el dispositivo.</translation>
 <translation id="6731757988219967594">Aplicar filtros de contenido para adultos a los sitios principales (pero no a los iframes incorporados)</translation>
 <translation id="6734521799274931721">Controlar la disponibilidad de "Network File Shares" para el Sistema operativo Chrome</translation>
 <translation id="6735701345096330595">Habilitar la corrección ortográfica de idiomas</translation>
@@ -3779,9 +3844,9 @@
 
       Si estableces la política <ph name="VARIATIONS_ENABLED_OPTION_NAME" /> (valor 0) o no la estableces, se podrán aplicar todas las variaciones en el navegador.
 
-      Si la estableces <ph name="CRITICAL_VARIATIONS_ONLY_OPTION_NAME" /> (valor 1), se permitirá solo la aplicación de las variaciones que se consideren correcciones de estabilidad o seguridad críticas en <ph name="PRODUCT_NAME" />.
+      Si estableces <ph name="CRITICAL_VARIATIONS_ONLY_OPTION_NAME" /> (valor 1), se permitirá solo la aplicación de las variaciones que se consideren correcciones de estabilidad o seguridad críticas en <ph name="PRODUCT_NAME" />.
 
-      Si la estableces <ph name="VARIATIONS_DISABLED_OPTION_NAME" /> (valor 2), no se permitirá la aplicación de ninguna variación en el navegador. Ten en cuenta que no se recomienda este modo porque podría impedir que los desarrolladores de <ph name="PRODUCT_NAME" /> proporcionen correcciones de seguridad críticas de manera oportuna.</translation>
+      Si estableces <ph name="VARIATIONS_DISABLED_OPTION_NAME" /> (valor 2), no se permitirá la aplicación de ninguna variación en el navegador. Ten en cuenta que no se recomienda este modo porque podría impedir que los desarrolladores de <ph name="PRODUCT_NAME" /> proporcionen correcciones de seguridad críticas de manera oportuna.</translation>
 <translation id="6810445994095397827">Bloquear JavaScript en estos sitios</translation>
 <translation id="6813263547126514821">Encendido y apagado</translation>
 <translation id="681446116407619279">Esquemas de autenticación compatibles</translation>
@@ -4064,6 +4129,9 @@
 
       Nota: La política no afectará Google Drive ni el almacenamiento interno. Los usuarios podrán seguir accediendo a los archivos guardados en la carpeta de descargas.</translation>
 <translation id="7177857088692019405">Desbloqueo rápido</translation>
+<translation id="7179187054027029272">Si estableces la política como verdadera o no la estableces, los usuarios, las apps y las extensiones que cuenten con los permisos correspondientes podrán acceder al modo de pantalla completa (en el cual solo aparece el contenido web).
+
+      Si la estableces como falsa, los usuarios, las apps y las extensiones no podrán acceder al modo de pantalla completa.</translation>
 <translation id="718126088895133062">Esta política especifica el ID de usuario de la licencia de <ph name="PLUGIN_VM_NAME" /> para este dispositivo.</translation>
 <translation id="7185078796915954712">TLS 1.3</translation>
 <translation id="7187447094921703950">Habilita la política de administración energética para el cambio de pico de consumo de energía.
@@ -4642,6 +4710,11 @@
 <translation id="8140204717286305802">Informa sobre la lista de interfaces de red con sus tipos y direcciones de hardware al servidor.
 
       Si esta política se establece en "False", no se informará sobre la lista de interfaces.</translation>
+<translation id="8140907626566492348">Si estableces la política como verdadera o no la estableces, <ph name="PRODUCT_NAME" /> podrá mostrarles a los usuarios contenido sobre productos en pestaña completa.
+
+      Si estableces la política como falsa, <ph name="PRODUCT_NAME" /> no podrá mostrar contenido sobre productos en pestaña completa.
+
+      Si estableces la política, se podrá controlar la presentación de páginas de bienvenida que permiten a los usuarios acceder a <ph name="PRODUCT_NAME" />, elegir <ph name="PRODUCT_NAME" /> como navegador predeterminado o recibir información sobre funciones de productos.</translation>
 <translation id="8141795997560411818">Esta política no impide que el usuario use la app de Google Drive de Android. Si deseas evitar el acceso a Google Drive, también debes inhabilitar la instalación de su app.</translation>
 <translation id="8142894094385450823">Establecer la configuración regional recomendada para una sesión administrada</translation>
 <translation id="8146727383888924340">Permite a los usuarios canjear ofertas a través del Registro del Sistema operativo Chrome.</translation>
@@ -4662,6 +4735,9 @@
 
       Si esta política se inhabilita o no se establece, el acceso direcciona al usuario a los perfiles normales.</translation>
 <translation id="8158758865057576716">Habilita la creación de las copias de itinerancia para los datos de perfil de <ph name="PRODUCT_NAME" />.</translation>
+<translation id="8158897487095710470">Si estableces la política como verdadera, se mostrará una barra de favoritos en <ph name="PRODUCT_NAME" />. Si la estableces como falsa, los usuarios no podrán ver la barra de favoritos.
+
+      Si estableces la política, los usuarios no podrán cambiarla. Si no la estableces, los usuarios decidirán si usan esta función.</translation>
 <translation id="8159760979508295709">Habilita la función de accesibilidad para resaltar la posición del cursor.
 
           Esta función resalta el área que rodea al cursor del mouse mientras lo mueves.
@@ -4838,6 +4914,11 @@
 <translation id="8424255554404582727">Establecer la rotación predeterminada de la pantalla que se volverá a aplicar en cada reinicio</translation>
 <translation id="8426231401662877819">Rotar la pantalla hacia la derecha 90 grados</translation>
 <translation id="8433186206711564395">Opciones de red</translation>
+<translation id="843609873781525167">Si estableces la política como verdadera, <ph name="PRODUCT_NAME" /> revisará siempre al iniciarse si es el navegador predeterminado y se registrará automáticamente en caso de ser posible. Si la estableces como falsa, <ph name="PRODUCT_NAME" /> dejará de revisar si es el navegador predeterminado y se desactivarán los controles del usuario para esta opción.
+
+      Si no la estableces, <ph name="PRODUCT_NAME" /> permitirá que los usuarios decidan si será el navegador predeterminado y, en caso de no seleccionarlo, si se mostrarán las notificaciones para el usuario.
+
+      Nota para los administradores de <ph name="MS_WIN_NAME" />: Esta opción de configuración solo podrá habilitarse en máquinas con Windows 7. Para las versiones posteriores, el usuario debe implementar un archivo con "asociaciones de apps predeterminadas" que convierta a <ph name="PRODUCT_NAME" /> en el controlador de los protocolos <ph name="HTTPS_PROTOCOL" /> y <ph name="HTTP_PROTOCOL" /> (y, opcionalmente, el protocolo <ph name="FTP_PROTOCOL" /> y otros formatos de archivo). Consulta la Ayuda de Chrome ( https://support.google.com/chrome?p=make_chrome_default_win).</translation>
 <translation id="8445576299806775661">Después de cada actualización importante de la versión, Chrome creará una instantánea de ciertas porciones de los datos de navegación del usuario en caso de tener que realizar una reversión de emergencia en el futuro. Si se realiza una reversión de emergencia a una versión para la cual el usuario tiene una instantánea correspondiente, se restablecerán los datos de esa instantánea. Esto permitirá que los usuarios conserven opciones de configuración como los favoritos y los datos de la función Autocompletar.
 
       Si no se establece esta política, se usará el valor predeterminado "3".
@@ -4922,6 +5003,9 @@
 
           De lo contrario las combinaciones de teclas para las funciones de accesibilidad estarán habilitadas de forma predeterminada.</translation>
 <translation id="8525526490824335042">Contenedor de Linux</translation>
+<translation id="8537051350735478658">Si estableces la política como verdadera, se activarán las sugerencias de búsqueda en la barra de direcciones de <ph name="PRODUCT_NAME" />. Si la estableces como falsa, se desactivarán estas sugerencias de búsqueda.
+
+      Si estableces la política, los usuarios no podrán cambiarla. Si no la estableces, las sugerencias de búsqueda estarán activadas al principio, pero los usuarios podrán desactivarlas en cualquier momento.</translation>
 <translation id="8544375438507658205">Procesador HTML predeterminado para <ph name="PRODUCT_FRAME_NAME" /></translation>
 <translation id="8544465954173828789">Permite que los mensajes SMS se sincronicen desde el teléfono con la Chromebook</translation>
 <translation id="8548832052135586762">Establece la impresión como solo a color, solo monocromática o sin restricción del modo de color. Si no se configura la política, no se aplicará ninguna restricción.</translation>
@@ -5280,9 +5364,9 @@
           Nota: <ph name="DEVICE_ADVANCED_BATTERY_CHARGE_MODE_ENABLED_NAME" /> anula esta política si se especifica la política anterior.</translation>
 <translation id="9055835215213290877">Si estableces la política como "None", <ph name="PRODUCT_NAME" /> usará el tamaño predeterminado para guardar los archivos almacenados en caché que se encuentren en el disco. Los usuarios no podrán cambiar esta configuración.
 
-      Si estableces la política, <ph name="PRODUCT_NAME" /> usará el tamaño del almacenamiento en caché que proporciones, más allá de que los usuarios hayan especificado o no la marca --disk-cache-size. (Los valores expresados en megabytes se redondearán hacia arriba).
+      Si estableces la política, <ph name="PRODUCT_NAME" /> usará el tamaño del almacenamiento en caché que proporciones, independientemente de que los usuarios hayan especificado o no la función experimental --disk-cache-size. (Los valores expresados en megabytes se redondearán hacia arriba).
 
-      Si no estableces la política, <ph name="PRODUCT_NAME" /> usará el tamaño predeterminado. Los usuarios podrán cambiar la configuración mediante la marca --disk-cache-size.</translation>
+      Si no estableces la política, <ph name="PRODUCT_NAME" /> usará el tamaño predeterminado. Los usuarios podrán cambiar la configuración mediante la función experimental --disk-cache-size.</translation>
 <translation id="9077227880520270584">Temporizador para el acceso automático de la cuenta local del dispositivo</translation>
 <translation id="9084985621503260744">Especificar si la actividad de video afecta a la administración de energía</translation>
 <translation id="9088433379343318874">Habilitar el proveedor de contenido de un usuario supervisado</translation>
diff --git a/components/policy/resources/policy_templates_ru.xtb b/components/policy/resources/policy_templates_ru.xtb
index fb1fb46..1f6aa87 100644
--- a/components/policy/resources/policy_templates_ru.xtb
+++ b/components/policy/resources/policy_templates_ru.xtb
@@ -1979,7 +1979,7 @@
 
       – DisallowArc (или правило не настроено), переход с eCryptfs на ext4 не выполняется, и Android-приложения пользователя перестают запускаться.
 
-      Правило не применяется к пользователям с устройствами в режиме киоска.
+      Правило не применяется к пользователям устройств в режиме киоска.
 
       Внимание! Если задано значение Wipe или MinimalMigrate, локальные данные будут удалены.</translation>
 <translation id="3925377537407648234">Настроить разрешение дисплея и коэффициент масштабирования</translation>
@@ -2999,7 +2999,7 @@
 
       Это правило будет удалено в <ph name="PRODUCT_NAME" /> для Mac OS X версии 87, когда будет прекращена поддержка инструмента верификации прошлого поколения в Mac OS X.
       </translation>
-<translation id="5494917047563607689">Если правило не настроено или задано значение, которое меньше 1 МБ, <ph name="PRODUCT_OS_NAME" /> использует объем кеша по умолчанию для кеширования приложений и расширений при их установке несколькими пользователями одного устройства. Это позволяет избежать повторного скачивания контента.</translation>
+<translation id="5494917047563607689">Если правило не настроено или задано значение меньше 1 МБ, <ph name="PRODUCT_OS_NAME" /> использует объем кеша по умолчанию для кеширования приложений и расширений при их установке несколькими пользователями одного устройства. Это позволяет избежать повторного скачивания контента.</translation>
 <translation id="5498045818698736356">Позволяет указать список сайтов, которые устанавливаются без участия пользователя и которые нельзя удалить или отключить.
 
       Каждый элемент списка представляет собой объект, включающий обязательную переменную url и две необязательные – default_launch_container и create_desktop_shortcut. Переменная url – это URL устанавливаемого веб-приложения, а launch_container принимает значения window или tab (определяя, как откроется приложение после установки: в окне или во вкладке). Чтобы создать ярлык на рабочем столе компьютера с Linux или Windows, укажите для переменной create_desktop_shortcut значение True. Если значение default_launch_container не указано, приложение по умолчанию будет открываться во вкладке. Вне зависимости от значения default_launch_container пользователи могут самостоятельно указать, где будет открываться приложение. Если значение create_desktop_shortcuts не указано, ярлык на рабочем столе не будет создан. Размещение приложений во временном хранилище Chrome OS регулируется правилом <ph name="PINNED_LAUNCHER_APPS_POLICY_NAME" />.</translation>
@@ -3056,7 +3056,7 @@
 <translation id="5565178130821694365">Пароль необходимо вводить каждые 48 часов.</translation>
 <translation id="556564360355507488">Это правило позволяет выбрать, какие модификации можно применять на устройстве с <ph name="PRODUCT_OS_NAME" />, находящемся под управлением администраторов организации.
 
-      С помощью модификаций можно изменить <ph name="PRODUCT_OS_NAME" /> без установки новой версии путем выборочного включения и отключения уже имеющихся функций.
+      С помощью модификаций можно изменить <ph name="PRODUCT_OS_NAME" /> без установки новой версии, путем выборочного включения и отключения уже имеющихся функций.
 
       Если правило не настроено или установлен параметр <ph name="VARIATIONS_ENABLED_OPTION_NAME" /> (значение "0"), к <ph name="PRODUCT_OS_NAME" /> можно применять любые модификации.
 
@@ -3388,7 +3388,7 @@
 
       Если установлено значение "Блокировать загрузку и скачивание больших файлов", <ph name="PRODUCT_NAME" /> действует так же, как при значениях "Блокировать скачивание больших файлов" и "Блокировать загрузку больших файлов".
       </translation>
-<translation id="6082161804984853051">Если правило настроено, <ph name="PRODUCT_NAME" /> хранит кешированные файлы на диске в установленном вами каталоге независимо от того, указали или нет пользователи значение экспериментального параметра --disk-cache-dir.
+<translation id="6082161804984853051">Если правило настроено, <ph name="PRODUCT_NAME" /> хранит кешированные файлы на диске в установленном вами каталоге независимо от того, указали ли пользователи значение экспериментального параметра --disk-cache-dir.
 
       Если правило не настроено, <ph name="PRODUCT_NAME" /> использует каталог по умолчанию, однако пользователи могут его изменить с помощью экспериментального параметра --disk-cache-dir.
 
@@ -3853,7 +3853,7 @@
 <translation id="6795485990775913659">Разрешить печать только без ввода PIN-кода</translation>
 <translation id="6799657852647827750">Это правило позволяет выбрать, какие модификации можно применять к <ph name="PRODUCT_NAME" />.
 
-      С помощью модификаций можно изменить <ph name="PRODUCT_NAME" /> без установки новой версии путем выборочного включения и отключения уже имеющихся функций.
+      С помощью модификаций можно изменить <ph name="PRODUCT_NAME" /> без установки новой версии, путем выборочного включения и отключения уже имеющихся функций.
 
       Если правило не настроено или установлен параметр <ph name="VARIATIONS_ENABLED_OPTION_NAME" /> (значение "0"), к браузеру можно применять любые модификации.
 
@@ -5358,7 +5358,7 @@
           Примечание. Если настроено правило <ph name="DEVICE_ADVANCED_BATTERY_CHARGE_MODE_ENABLED_NAME" />, его значение будет иметь приоритет над этим правилом.</translation>
 <translation id="9055835215213290877">Если для правила задано значение None, <ph name="PRODUCT_NAME" /> использует объем кеша по умолчанию для хранения кешированных файлов на диске. В этом случае пользователи не могут изменить правило.
 
-      Если вы настроите правило, <ph name="PRODUCT_NAME" /> будет использовать установленный вами размер кеша независимо от того, указали или нет пользователи значение экспериментального параметра --disk-cache-size. Значения меньше нескольких мегабайтов округляются.
+      Если вы настроите правило, <ph name="PRODUCT_NAME" /> будет использовать установленный вами размер кеша независимо от того, указали ли пользователи значение экспериментального параметра --disk-cache-size. Значения меньше нескольких мегабайтов округляются.
 
       Если правило не настроено, <ph name="PRODUCT_NAME" /> использует объем по умолчанию. В этом случае пользователи могут менять размер кеша с помощью экспериментального параметра --disk-cache-size.</translation>
 <translation id="9077227880520270584">Таймер автоматического входа в локальный аккаунт</translation>
diff --git a/components/policy/resources/policy_templates_th.xtb b/components/policy/resources/policy_templates_th.xtb
index 738de6b2..604ec24 100644
--- a/components/policy/resources/policy_templates_th.xtb
+++ b/components/policy/resources/policy_templates_th.xtb
@@ -1957,7 +1957,7 @@
 
       * Migrate (หรือตัวเลือกที่ไม่รองรับ เช่น AskUser หรือ AskForEcryptfsArcUsers) หมายความว่าไดเรกทอรีจะย้ายข้อมูลไปยัง ext4 โดยอัตโนมัติเมื่อลงชื่อเข้าใช้ โดยไม่ต้องขอคำยินยอมจากผู้ใช้
 
-      * Wipe หรือ MinimalMigrate หมายความว่าเมื่อลงชื่อเข้าใช้ ไดเรกทอรีหลักใหม่ที่เข้ารหัส ext4 จะแทนที่ไดเรกทอรีที่เข้ารหัส ecryptfs เพื่อช่วยให้ผู้ใช้ไม่ลงชื่อเข้าใช้ซ้ำ MinimalMigrate จะพยายามรักษาโทเค็นการลงชื่อเข้าใช้ไว้
+      * Wipe หรือ MinimalMigrate หมายความว่าเมื่อลงชื่อเข้าใช้ ไดเรกทอรีหลักใหม่ที่เข้ารหัส ext4 จะแทนที่ไดเรกทอรีเก่าที่เข้ารหัส ecryptfs เพื่อช่วยให้ผู้ใช้ไม่ลงชื่อเข้าใช้ซ้ำ MinimalMigrate จะพยายามรักษาโทเค็นการลงชื่อเข้าใช้ไว้
 
       * DisallowArc หรือไม่ได้ตั้งค่าจะทำให้ไม่มีการย้ายข้อมูล และแอป Android ของผู้ใช้จะหยุดทำงาน
 
@@ -3355,9 +3355,9 @@
 
       หากตั้งค่านโยบายนี้เป็น "บล็อกการอัปโหลดและดาวน์โหลดไฟล์ขนาดใหญ่" <ph name="PRODUCT_NAME" /> จะทำงานตามกฎที่อธิบายไว้ภายใต้นโยบาย "บล็อกการดาวน์โหลดขนาดใหญ่" และ "บล็อกการอัปโหลดขนาดใหญ่"
       </translation>
-<translation id="6082161804984853051">การตั้งค่านโยบายทำให้ <ph name="PRODUCT_NAME" /> ใช้ไดเรกทอรีที่คุณให้ไว้สำหรับจัดเก็บไฟล์ที่แคชไว้ในดิสก์ ไม่ว่าจะระบุการติดธง --disk-cache-dir หรือไม่ก็ตาม
+<translation id="6082161804984853051">การตั้งค่านโยบายทำให้ <ph name="PRODUCT_NAME" /> ใช้ไดเรกทอรีที่คุณให้ไว้สำหรับจัดเก็บไฟล์ที่แคชไว้ในดิสก์ ไม่ว่าจะระบุการตั้งค่าสถานะ --disk-cache-dir หรือไม่ก็ตาม
 
-      หากไม่ได้ตั้งค่า <ph name="PRODUCT_NAME" /> จะใช้ไดเรกทอรีแคชเริ่มต้น แต่ผู้ใช้จะเปลี่ยนการตั้งค่านั้นได้ด้วยการติดธงบรรทัดคำสั่ง --disk-cache-dir
+      หากไม่ได้ตั้งค่า <ph name="PRODUCT_NAME" /> จะใช้ไดเรกทอรีแคชเริ่มต้น แต่ผู้ใช้จะเปลี่ยนการตั้งค่านั้นได้ด้วยการตั้งค่าสถานะบรรทัดคำสั่ง --disk-cache-dir
 
       <ph name="PRODUCT_NAME" /> จะจัดการเนื้อหาของไดเรกทอรีรูทของวอลุ่ม ดังนั้นเพื่อหลีกเลี่ยงการสูญหายของข้อมูลหรือข้อผิดพลาดอื่นๆ โปรดอย่าตั้งค่านโยบายนี้เป็นไดเรกทอรีรูทหรือไดเรกทอรีอื่นที่ใช้สำหรับวัตถุประสงค์อื่นๆ ดูตัวแปรที่คุณใช้ได้ ( https://www.chromium.org/administrators/policy-list-3/user-data-directory-variables )</translation>
 <translation id="6083631234867522991">Windows (ไคลเอ็นต์ของ Windows):</translation>
@@ -3824,7 +3824,7 @@
 
       การตั้งค่า <ph name="CRITICAL_VARIATIONS_ONLY_OPTION_NAME" /> (ค่า 1) จะอนุญาตให้ใช้เฉพาะรูปแบบที่ถือว่าเป็นการแก้ไขด้านความปลอดภัยที่สำคัญมากหรือการแก้ไขด้านความเสถียรกับ <ph name="PRODUCT_NAME" /> เท่านั้น
 
-      การตั้งค่า <ph name="VARIATIONS_DISABLED_OPTION_NAME" /> (ค่า 2) จะไม่อนุญาตให้ใช้รูปแบบใดก็ตามกับเบราว์เซอร์ โปรดทราบว่าโหมดนี้อาจขัดขวางไม่ให้นักพัฒนาซอฟต์แวร์ของ <ph name="PRODUCT_NAME" /> ทำการแก้ไขด้านความปลอดภัยที่สำคัญมากได้อย่างทันท่วงที และด้วยเหตุนี้จึงไม่แนะนำให้ใช้โหมดนี้</translation>
+      การตั้งค่า <ph name="VARIATIONS_DISABLED_OPTION_NAME" /> (ค่า 2) จะไม่อนุญาตให้ใช้รูปแบบใดก็ตามกับเบราว์เซอร์ โปรดทราบว่าโหมดนี้อาจขัดขวางไม่ให้นักพัฒนาแอปของ <ph name="PRODUCT_NAME" /> ทำการแก้ไขด้านความปลอดภัยที่สำคัญมากได้อย่างทันท่วงที และด้วยเหตุนี้จึงไม่แนะนำให้ใช้โหมดนี้</translation>
 <translation id="6810445994095397827">ปิดกั้น JavaScript บนไซต์เหล่านี้</translation>
 <translation id="6813263547126514821">การเปิดและปิดระบบ</translation>
 <translation id="681446116407619279">สกีมการตรวจสอบสิทธิ์ที่ได้รับการสนับสนุน</translation>
@@ -5321,9 +5321,9 @@
           หมายเหตุ: <ph name="DEVICE_ADVANCED_BATTERY_CHARGE_MODE_ENABLED_NAME" /> จะลบล้างนโยบายนี้หากระบุนโยบายเดิมไว้</translation>
 <translation id="9055835215213290877">การตั้งค่านโยบายนี้เป็น "ไม่มี" ทำให้ <ph name="PRODUCT_NAME" /> ใช้ขนาดแคชเริ่มต้นในการจัดเก็บไฟล์ที่แคชไว้ในดิสก์ โดยที่ผู้ใช้จะเปลี่ยนแปลงไม่ได้
 
-      หากคุณตั้งค่านโยบายนี้ <ph name="PRODUCT_NAME" /> จะใช้ขนาดแคชที่คุณระบุไว้ ไม่ว่าผู้ใช้จะระบุการติดธง --disk-cache-size หรือไม่ก็ตาม (ระบบจะปัดเศษค่าที่ต่ำกว่า 2-3 เมกะไบต์)
+      หากคุณตั้งค่านโยบายนี้ <ph name="PRODUCT_NAME" /> จะใช้ขนาดแคชที่คุณระบุไว้ ไม่ว่าผู้ใช้จะระบุการตั้งค่าสถานะ --disk-cache-size หรือไม่ก็ตาม (ระบบจะปัดเศษค่าที่ต่ำกว่า 2-3 เมกะไบต์)
 
-      หากไม่ได้ตั้งค่า <ph name="PRODUCT_NAME" /> จะใช้ขนาดเริ่มต้น ผู้ใช้เปลี่ยนการตั้งค่าดังกล่าวได้โดยใช้การติดธง --disk-cache-size</translation>
+      หากไม่ได้ตั้งค่า <ph name="PRODUCT_NAME" /> จะใช้ขนาดเริ่มต้น ผู้ใช้เปลี่ยนการตั้งค่าดังกล่าวได้โดยใช้การตั้งค่าสถานะ --disk-cache-size</translation>
 <translation id="9077227880520270584">ตัวจับเวลาการเข้าสู่ระบบอัตโนมัติไปยังบัญชีภายในอุปกรณ์</translation>
 <translation id="9084985621503260744">ระบุว่ากิจกรรมวิดีโอมีผลต่อการจัดการพลังงานหรือไม่</translation>
 <translation id="9088433379343318874">เปิดใช้ผู้ให้บริการเนื้อหาสำหรับผู้ใช้ภายใต้การดูแล</translation>
diff --git a/components/policy/resources/policy_templates_tr.xtb b/components/policy/resources/policy_templates_tr.xtb
index 98ab97a..9b5bda59 100644
--- a/components/policy/resources/policy_templates_tr.xtb
+++ b/components/policy/resources/policy_templates_tr.xtb
@@ -1426,7 +1426,7 @@
 
         UYARI: Deneysel politikalar desteklenmez ve tarayıcının gelecekteki sürümünde bildirimde bulunmaksızın değiştirilebilir veya kaldırılabilir.
 
-        Deneysel bir politika tamamlanmamış olabilir veya hâlâ bilinen ya da bilinmeyen kusurlar içerebilir. Herhangi bir bildirimde bulunulmadan değiştirilebilir veya hatta kaldırılabilir. Deneysel politikaları etkinleştirdiğinizde tarayıcı verileri kaybolabilir ya da güvenliğiniz veya gizliliğiniz ihlal edilebilir.
+        Deneysel bir politika tamamlanmamış olabilir veya hâlâ bilinen ya da bilinmeyen kusurlar içerebilir. Herhangi bir bildirimde bulunulmadan değiştirilebilir, hatta kaldırılabilir. Deneysel politikaları etkinleştirdiğinizde tarayıcı verileri kaybolabilir ya da güvenliğiniz veya gizliliğiniz ihlal edilebilir.
 
         Listede olmayan bir politika resmi olarak yayınlanmadıysa Chrome'un Beta ve Kararlı sürümlerinde politikanın değeri göz ardı edilir.
 
diff --git a/components/policy/resources/policy_templates_zh-TW.xtb b/components/policy/resources/policy_templates_zh-TW.xtb
index 90a84c4c..3c3dd08 100644
--- a/components/policy/resources/policy_templates_zh-TW.xtb
+++ b/components/policy/resources/policy_templates_zh-TW.xtb
@@ -326,6 +326,9 @@
 <translation id="1583248206450240930">根據預設使用 <ph name="PRODUCT_FRAME_NAME" /></translation>
 <translation id="1588240398285670601">瀏覽器設定</translation>
 <translation id="1599424828227887013">在 Android 裝置上為指定來源啟用網站隔離</translation>
+<translation id="159946228300522107">如果將這項政策設為 True,Chrome 首次執行時會將第一個顯示的視窗最大化。
+
+      如果將這項政策設為 False 或不設定,Chrome 會視螢幕大小而定,將第一個視窗最大化。</translation>
 <translation id="1608755754295374538">系統會直接授權存取音訊擷取裝置而不需提示的網址</translation>
 <translation id="1615221548356595305">即使在用戶端憑證已有人使用的情況下,仍允許這些主機合併 HTTP/2 連線</translation>
 <translation id="1615855314789673708">提供 Wilco DTC (診斷與遙測控制器) 設定功能。
@@ -385,6 +388,9 @@
         將網址規則運算式新增到 |url_list|,即可將符合清單中任何規則運算式的網址加入許可清單。
         將應用程式的 |app_id| 和 |app_type| 新增到 |app_list|,即可將應用程式加入許可清單。
        </translation>
+<translation id="171511968762040550">如果將這項政策設為 True 或不設定,使用者可以新增、移除或修改書籤。
+
+      如果將這項政策設為 False,使用者無法新增、移除或修改書籤,但仍可以使用現有書籤。</translation>
 <translation id="1715151459541210849">啟用語音輸入無障礙功能</translation>
 <translation id="1717817358640580294">如未設定這項政策,當 Chrome 清理功能偵測到垃圾軟體時,可能會根據 SafeBrowsingExtendedReportingEnabled 設定的政策,將掃描作業的相關中繼資料回報給 Google。回報完畢後,Chrome 清理功能會詢問使用者是否要將偵測到的垃圾軟體清除。使用者可以選擇將清理作業的執行結果分享給 Google,讓日後的垃圾軟體偵測作業更精確。分享的結果包括檔案中繼資料、自動安裝的擴充功能和登錄機碼,詳情請見《Chrome 隱私權白皮書》。
 
@@ -747,6 +753,12 @@
 <translation id="2214880135980649323">如果將這項政策設為啟用,系統將允許由企業政策安裝的擴充功能使用 Enterprise Hardware Platform API。
       如果將這項政策設為停用或不予設定,則所有擴充功能皆無法使用 Enterprise Hardware Platform API。
       這項政策也適用於元件擴充功能,例如 Hangout Services 擴充功能。</translation>
+<translation id="2215238871726750562">如果將這項政策設為 True,系統不會在工作階段開始時啟動瀏覽器視窗。
+
+      如果將這項政策設為 False 或不設定,系統將可啟動視窗。
+
+      注意:瀏覽器視窗可能會因為其他政策或指令列標記而無法啟動。</translation>
+<translation id="2223582957891074498">如果將這項政策設為 True,使用者無法使用鍵盤快速鍵或擴充功能 API 來擷取螢幕畫面。如果將這項政策設為 False,使用者可以擷取螢幕畫面。</translation>
 <translation id="2223598546285729819">預設通知設定</translation>
 <translation id="2231817271680715693">第一次執行時從預設瀏覽器匯入瀏覽記錄</translation>
 <translation id="2236488539271255289">不允許任何網站設定本機資料</translation>
@@ -778,6 +790,9 @@
 
       如果你並未設置這項設定,則使用者可自行選擇是否要使用拼字檢查服務。</translation>
 <translation id="229322770310505679">啟用不可部分完成的政策群組概念</translation>
+<translation id="22941467117331786">如果將這項政策設為 True,在有效工作階段期間且螢幕未鎖定時,系統匣中會顯示大型的紅色登出按鈕。
+
+      如果將這項政策設為 False 或不設定,系統匣中不會顯示任何按鈕。</translation>
 <translation id="2294382669900758280">即使將這項政策設為 <ph name="TRUE" />,在 Android 應用程式中播放的影片仍不會受到影響。</translation>
 <translation id="2299220924812062390">指定停用的外掛程式清單</translation>
 <translation id="2303795211377219696">啟用信用卡的自動填入功能</translation>
@@ -2434,6 +2449,9 @@
 <translation id="4802905909524200151">設定 <ph name="TPM_FIRMWARE_UPDATE_TPM" /> 韌體更新行為</translation>
 <translation id="4804828344300125154">�在使用者登出時一律重新啟動。</translation>
 <translation id="4807950475297505572">移除近期登入次數最少的使用者,直到有足夠的可用空間</translation>
+<translation id="4812270373673968774">如果將這項政策設為 Always,系統會自動隱藏 <ph name="PRODUCT_OS_NAME" />檔案櫃。如果將這項政策設為 Never,系統一律不會自動隱藏檔案櫃。
+
+      如果設定這項政策,使用者將無法變更。如果未設定,使用者可自行決定是否要自動隱藏檔案櫃。</translation>
 <translation id="4816674326202173458">允許企業使用者成為主要或次要使用者 (非管理化環境中使用者的預設行為)</translation>
 <translation id="4826326557828204741">使用電池電源的情況下,系統在達到閒置延遲時間時所採取的動作</translation>
 <translation id="4830531683854509779">回報 SoC 元件的硬體統計資料。
@@ -2511,6 +2529,9 @@
 <translation id="4986560318567565414">從替代瀏覽器切換到 Chrome 所使用的路徑。</translation>
 <translation id="4988291787868618635">在達到閒置延遲時間時要採取的動作</translation>
 <translation id="500149597848135831">啟用所有變化版本</translation>
+<translation id="5017369989680827157">如果將這項政策設為 True 或不設定,使用者即可控制 UI 中的地址自動填入功能。
+
+      如果將這項政策設為 False,自動填入功能一律不會建議或填入地址資訊,也不會在使用者瀏覽網頁時儲存其提交的其他地址資訊。</translation>
 <translation id="5023555740504506178">如果啟用或不設定這項政策 (預設值),網頁可以使用
       螢幕畫面分享 API (例如 getDisplayMedia() 或是螢幕畫面擷取擴充功能 API),
       來提示使用者選取要擷取的分頁、視窗或桌面。
@@ -2552,6 +2573,9 @@
 <translation id="5073609397321802133">如果將這項政策設為 False,系統將禁止使用者自訂新分頁的背景。即使日後將這項政策設為 True,系統仍會永久移除任何現有的自訂背景。
 
       如果不設定這項政策或將其設為 True,使用者可以自訂新分頁的背景。</translation>
+<translation id="5075190314377370852">如果將這項政策設為 True,<ph name="PRODUCT_NAME" /> 一律會針對在本機上安裝的 CA 憑證所簽署的成功驗證伺服器憑證執行撤銷檢查。如果 <ph name="PRODUCT_NAME" /> 無法取得撤銷狀態資訊,<ph name="PRODUCT_NAME" /> 會將這些憑證視為已撤銷 (作業失敗)。
+
+      如果將這項政策設為 False 或不設定,<ph name="PRODUCT_NAME" /> 會使用現有的線上撤銷檢查設定。</translation>
 <translation id="5075834892754086022">如果設定這項政策,系統會強制使用政策所設定的 PIN 碼長度
           下限。(PIN 碼長度的絕對下限為 1;系統會將低於 1
           的值視為 1 處理。)
@@ -2620,6 +2644,11 @@
       最短間隔為 30 秒,最長間隔為 24 小時。
       超過範圍的間隔值會被限制在範圍內。</translation>
 <translation id="5163002264923337812">啟用舊版網頁式登入流程</translation>
+<translation id="516520353995300280">設定這項政策後,系統不會強制要求列出的舊版憑證授權單位 (CA) (由包含指定 <ph name="SUBJECT_PUBLIC_KEY_INFO" /> 雜湊的憑證鏈所組成) 依憑證透明化規定公開憑證。企業主機可繼續使用原本不受信任的憑證 (因未依規定對外公開)。視為舊版 CA 的 CA 憑證必須使用 <ph name="SUBJECT_PUBLIC_KEY_INFO" /> 雜湊,才能不強制要求公開憑證。舊版 CA 是受到一或多個 <ph name="PRODUCT_NAME" /> 支援的作業系統公開信任,但不受 Android 開放原始碼計畫或 <ph name="PRODUCT_OS_NAME" />信任的 CA。
+
+      指定 <ph name="SUBJECT_PUBLIC_KEY_INFO" /> 雜湊的方法是串連雜湊演算法名稱、斜線以及套用到指定憑證 <ph name="SUBJECT_PUBLIC_KEY_INFO" /> (採 DER 編碼) 雜湊演算法所採用的 Base64 編碼。Base64 編碼格式符合 SPKI 指紋編碼的格式。僅支援 sha256 雜湊演算法,系統會忽略其他雜湊演算法。
+
+      如果未設定這項政策,凡是應依憑證透明化規定公開而未公開的憑證,<ph name="PRODUCT_NAME" /> 都會將其視為不受信任的憑證。</translation>
 <translation id="5168529971295111207">這項政策已遭淘汰,請改用 ProxyMode。
 
           這項政策可讓你指定 <ph name="PRODUCT_NAME" /> 使用的 Proxy 伺服器,並禁止使用者變更 Proxy 設定。
@@ -2761,6 +2790,9 @@
 
       如果未設定這項政策,或是將這項政策設為空白字串或無效的通訊埠範圍,WebRTC 即可使用任何可用的本機 UDP 通訊埠。</translation>
 <translation id="5290940294294002042">指定使用者可以任意啟用或停用的外掛程式清單</translation>
+<translation id="5293044154216294358">如果將這項政策設為 True,使用者就可以玩恐龍遊戲。如果將這項政策設為 False,使用者無法在裝置處於離線狀態時玩恐龍復活節彩蛋遊戲。
+
+      如果未設定這項政策,使用者無法在已註冊的 <ph name="PRODUCT_OS_NAME" />上玩恐龍復活節彩蛋遊戲,但可以在其他環境下玩這個遊戲。</translation>
 <translation id="5306186200045823863">信任 Symantec 公司的舊版 PKI 基礎架構</translation>
 <translation id="5307432759655324440">無痕模式適用性</translation>
 <translation id="5311275381462687162">預設的舊版 <ph name="ATTRIBUTE_SAMESITE_NAME" /> Cookie 行為設定</translation>
@@ -3041,6 +3073,9 @@
 
       注意:這項政策僅適用於 Android 裝置上的 Chrome,且相關裝置必須配備超過 1GB 的 RAM。如要在非 Android 平台上套用這項政策,請使用 IsolateOrigins。
       </translation>
+<translation id="5595998409088126162">你可以透過這項政策來設定書籤清單,其中的每個書籤都是一個包含「<ph name="NAME" />」和「<ph name="URL_LABEL" />」索引鍵的條目。這些索引鍵會指定書籤的名稱和目標網址。管理員如果要設定子資料夾,可以定義一個書籤,但不要指定「<ph name="URL_LABEL" />」索引鍵,並額外指定「<ph name="CHILDREN" />」索引鍵。這個索引鍵也會包含書籤清單,其中某些書籤也可以是資料夾。Chrome 會將有缺漏的網址修補完整,就像你在網址列中輸入網址時一樣。舉例來說,系統會自動將「<ph name="GOOGLE_COM" />」改成「<ph name="HTTPS_GOOGLE_COM" />」。
+
+      使用者無法變更書籤所在的資料夾,不過可以從書籤列將其隱藏。資料夾的名稱為「受管理書籤」,但使用者也可以在書籤清單中加入一個內含「<ph name="TOPLEVEL_NAME" />」索引鍵的條目,並將索引鍵值設為你想使用的資料夾名稱。受管理書籤不會同步到使用者帳戶,也無法透過擴充功能修改。</translation>
 <translation id="5599461642204007579"><ph name="MS_AD_NAME" /> 管理設定</translation>
 <translation id="5618398258385745432">我們先前曾以類似設定來控管使用者是否可查看密碼,但在新增重新驗證功能後,該設定與這項政策已不再適用於 Chrome 的運作方式。目前 Chrome 的運作方式,相當於這項政策禁止在密碼管理員設定頁面以純文字顯示密碼。也就是說,設定頁面只會顯示預留位置,使用者必須點選 [顯示] 並重新驗證 (如果適用),Chrome 才會顯示密碼。這項政策的原始說明如下:
 
@@ -3079,6 +3114,9 @@
       如將這項政策設為 0,就代表關閉驗證資料快取功能,這可能會導致關聯使用者的登入速度大幅變慢,因為使用者每次登入,系統都必須擷取領域專屬資料。
 
       請注意,即使是針對暫時性使用者,系統也會快取領域資料。如要避免追蹤暫時性使用者的領域,你必須關閉這項快取功能。</translation>
+<translation id="5700097087679928356">如果將這項政策設為 0 (預測值),你將可存取開發人員工具和 JavaScript 控制台,但無法在由企業政策安裝的擴充功能中進行存取。如果將這項政策設為 1,你將可在所有情況下存取開發人員工具和 JavaScript 控制台,在由企業政策安裝的擴充功能中也能進行存取。如果將這項政策設為 2,你將無法存取開發人員工具,也無法檢查網站元素。
+      
+這項設定也會停用透過鍵盤快速鍵、選單項目或內容選單項目來開啟開發人員工具或 JavaScript 控制台的功能。</translation>
 <translation id="570062449808736508">如果將這項政策設為非空白字串,WebView 就會讀取內容提供者 (擁有指定授權單位名稱) 的網址限制設定。</translation>
 <translation id="5708969689202733975">設定允許的快速解鎖模式</translation>
 <translation id="5711016543513883877">
@@ -3325,6 +3363,11 @@
 <translation id="6099853574908182288">預設列印色彩模式</translation>
 <translation id="6102342563050263313">啟用捲動至網址片段所指定文字的功能</translation>
 <translation id="6107642964266628393">控管 Chrome 作業系統的更新方式和更新時間。</translation>
+<translation id="6110478331147706293">設定這項政策後,系統不會要求指定網址中的主機名稱依憑證透明化規定公開憑證。雖然這會讓系統更難以偵測到誤用憑證的情形,但主機可繼續使用原本不受信任的憑證 (因未依規定對外公開)。
+
+      如果未設定這項政策,凡是應依憑證透明化規定公開而未公開的憑證,<ph name="PRODUCT_NAME" /> 都會將其設為不受信任的憑證。
+
+      網址格式必須符合 https://www.chromium.org/administrators/url-blacklist-filter-format 的規定。不過,由於單憑指定的主機名稱即可判定憑證有效 (忽略網址配置、通訊埠或路徑),因此 <ph name="PRODUCT_NAME" /> 只會檢視網址的主機名稱部分 (不支援含萬用字元的主機名稱)。</translation>
 <translation id="6111936128861357925">允許 Dinosaur Easter Egg Game (恐龍復活節彩蛋遊戲)</translation>
 <translation id="6114416803310251055">淘汰的</translation>
 <translation id="6133088669883929098">允許所有網站使用金鑰產生功能</translation>
@@ -3358,6 +3401,11 @@
           如需詳細範例,請造訪:
           <ph name="PROXY_HELP_URL" />。</translation>
 <translation id="6178075938488052838">這項政策可控管哪些使用者能夠啟動 <ph name="PRODUCT_OS_NAME" />工作階段,但不會禁止使用者在 Android 應用程式中登入其他 Google 帳戶。如要禁止使用者登入其他 Google 帳戶,你可以在 <ph name="ARC_POLICY_POLICY_NAME" /> 中設定 Android 專屬的 <ph name="ACCOUNT_TYPES_WITH_MANAGEMENT_DISABLED_CLOUDDPC_POLICY_NAME" /> 政策。</translation>
+<translation id="6183327369896253878">你可以透過這項政策修正 <ph name="PRODUCT_OS_NAME" />在啟動器列中顯示為固定應用程式的應用程式 ID,且使用者無法進行變更。
+
+      請透過應用程式 ID 來指定 Chrome 應用程式 (例如 pjkljhegncpnkpknbcohdijeoejaedia);透過應用程式套件名稱來指定 Android 應用程式 (例如 com.google.android.gm);透過 <ph name="WEB_APP_INSTALL_FORCE_LIST_POLICY_NAME" /> 中使用的應用程式網址來指定網頁應用程式 (例如 https://google.com/maps)。
+
+      如果不設定這項政策,使用者將可變更啟動器中的固定應用程式清單。</translation>
 <translation id="6190022522129724693">預設彈出視視窗設定</translation>
 <translation id="6190367314942602985">回報使用者身分識別資訊</translation>
 <translation id="6195802366906945965">決定是否使用內建憑證驗證器來驗證伺服器憑證</translation>
@@ -3474,6 +3522,9 @@
 
       如果設定這項政策,你可以設定是否允許使用者登入 <ph name="PRODUCT_NAME" />。將這項政策設為「False」後,將會導致使用 chrome.identity API 的應用程式和擴充功能無法運作,因此建議你改用 SyncDisabled。</translation>
 <translation id="6378076389057087301">指定會影響電源管理的音訊活動</translation>
+<translation id="6378393933102834628">如果將這項政策設為 True,系統會顯示應用程式捷徑。如果將這項政策設為 False,系統一律不會顯示應用程式捷徑。
+
+      如果設定這項政策,使用者將無法變更。如果未設定,使用者可以從書籤列內容選單中設定要顯示或隱藏應用程式捷徑。</translation>
 <translation id="637934607141010488">回報最近登入的裝置使用者清單。
 
       如果這項政策設為 False,則不會回報這些使用者。</translation>
@@ -3689,6 +3740,17 @@
 <translation id="6689792153960219308">回報硬體狀態</translation>
 <translation id="6698632841807204978">啟用單色列印</translation>
 <translation id="6699880231565102694">為遠端存取主機啟用雙重驗證機制</translation>
+<translation id="6703251016607733593">設定這項政策後,系統不會強制要求列出的 <ph name="SUBJECT_PUBLIC_KEY_INFO" /> 雜湊依憑證透明化規定公開憑證。企業主機可繼續使用原本不受信任的憑證 (因未依規定對外公開)。雜湊必須符合以下其中一項條件,才能不強制要求公開憑證:
+
+      * 雜湊是伺服器憑證的 <ph name="SUBJECT_PUBLIC_KEY_INFO" /> 雜湊。
+
+      * 雜湊是憑證鏈中的憑證授權單位 (CA) 憑證所使用的 <ph name="SUBJECT_PUBLIC_KEY_INFO" /> 雜湊,且該 CA 憑證受到 X.509v3 nameConstraints 擴充功能的限制。此外,permittedSubtrees 中有一或多個 directoryName nameConstraints,且 directoryName 具有 organizationName 屬性。
+
+      * 雜湊是憑證鏈中的 CA 憑證所使用的 <ph name="SUBJECT_PUBLIC_KEY_INFO" /> 雜湊,且該 CA 憑證的憑證主體中具有一或多個 organizationName 屬性。此外,伺服器的憑證具有數量與順序皆相同的 organizationName 屬性,且其中的位元對位元值也完全吻合。
+
+      指定 <ph name="SUBJECT_PUBLIC_KEY_INFO" /> 雜湊的方法是串連雜湊演算法名稱、斜線以及套用到指定憑證 <ph name="SUBJECT_PUBLIC_KEY_INFO" /> (採 DER 編碼) 雜湊演算法所採用的 Base64 編碼。Base64 編碼格式符合 SPKI 指紋編碼的格式。僅支援 sha256 雜湊演算法,系統會忽略其他雜湊演算法。
+
+      如果未設定這項政策,凡是應依憑證透明化規定公開而未公開的憑證,<ph name="PRODUCT_NAME" /> 都會將其視為不受信任的憑證。</translation>
 <translation id="6704515759227307131">這項政策已遭淘汰,並已替換為 AdvancedProtectionAllowed。
 
       這項政策可控管已加入進階保護計畫的使用者是否可以將下載內容傳送至 Google 進行惡意軟體掃描。如果設為 True 或不予設定,系統會提示已加入計畫的使用者將檔案傳送至 Google 進行深度掃描。如果使用者選取「掃描」,系統會將其下載內容傳送至 Google。如果設為 False,系統不會提示使用者,也不會將其下載內容傳送至 Google。</translation>
@@ -3699,6 +3761,9 @@
           從 <ph name="PRODUCT_NAME" /> 的第 76 版開始,如果不設定這項政策,瀏覽器會預設採用政策停用時的行為。
 
           從 <ph name="PRODUCT_NAME" /> 的第 78 版開始,瀏覽器會忽略這項政策,並將其視為已停用。</translation>
+<translation id="672496466524161417">如果將這項政策設為 None 或不設定,使用者將可管理憑證。如果將這項政策設為 2,使用者只能檢視憑證,而無法進行管理。
+
+      如果將這項政策設為 1,使用者將可管理使用者憑證,但無法管理裝置通用的憑證。</translation>
 <translation id="6731757988219967594">針對成人內容篩選頂層網站 (但不篩選嵌入的 iframe)</translation>
 <translation id="6734521799274931721">控管是否允許在 Chrome 作業系統使用網路檔案共用功能</translation>
 <translation id="6735701345096330595">強制執行拼字檢查的語言</translation>
@@ -4008,6 +4073,9 @@
 
       注意:這項政策不會影響 Google 雲端硬碟和內部儲存空間。使用者仍可存取「下載內容」資料夾中儲存的檔案。</translation>
 <translation id="7177857088692019405">快速解鎖</translation>
+<translation id="7179187054027029272">如果將這項政策設為 True 或不設定,具有適當權限的使用者、應用程式和擴充功能將可進入全螢幕模式 (僅顯示網頁內容)。
+
+      如果將這項政策設為 False,使用者、應用程式和擴充功能將無法進入全螢幕模式。</translation>
 <translation id="718126088895133062">這項政策會為這部裝置指定 <ph name="PLUGIN_VM_NAME" /> 授權使用者 ID。</translation>
 <translation id="7185078796915954712">TLS 1.3</translation>
 <translation id="7187447094921703950">啟用「用電尖峰轉移」電源管理政策。
@@ -4579,6 +4647,11 @@
 <translation id="8140204717286305802">將網路介面清單及其類型和硬體位址回報給伺服器。
 
       如果這項政策設為 False,則不會回報介面清單。</translation>
+<translation id="8140907626566492348">如果將這項政策設為 True 或不設定,<ph name="PRODUCT_NAME" /> 將能以整個分頁向使用者顯示產品資訊。
+
+      如果將這項政策設為 False,<ph name="PRODUCT_NAME" /> 無法以整個分頁顯示產品資訊。
+
+      你可以透過這項政策控管要如何顯示可協助使用者登入 <ph name="PRODUCT_NAME" /> 的歡迎頁面、將 <ph name="PRODUCT_NAME" /> 設為使用者的預設瀏覽器,或是向使用者顯示產品功能。</translation>
 <translation id="8141795997560411818">這項政策不會禁止使用者使用 Android Google 雲端硬碟應用程式。如要禁止存取 Google 雲端硬碟,則必須一併禁止安裝 Android Google 雲端硬碟應用程式。</translation>
 <translation id="8142894094385450823">針對受管理工作階段設定建議語言代碼</translation>
 <translation id="8146727383888924340">允許使用者透過 Chrome OS Registration 兌換優惠</translation>
@@ -4599,6 +4672,9 @@
 
       如果將這項政策設為停用或不予設定,登入時會導向一般設定檔。</translation>
 <translation id="8158758865057576716">允許建立 <ph name="PRODUCT_NAME" /> 設定檔資料的漫遊複本。</translation>
+<translation id="8158897487095710470">如果將這項政策設為 True,系統會在 <ph name="PRODUCT_NAME" /> 中顯示書籤列。如果將這項政策設為 False,使用者一律不會看到書籤列。
+
+      如果設定這項政策,使用者將無法變更。如果未設定,使用者可自行決定是否要使用這項功能。</translation>
 <translation id="8159760979508295709">啟用游標醒目顯示無障礙功能。
 
           這項功能會在使用者移動滑鼠游標時,醒目顯示游標周圍的區域。
@@ -4765,6 +4841,11 @@
 <translation id="8424255554404582727">設定畫面旋轉預設值 (每次重新啟動皆重新套用)</translation>
 <translation id="8426231401662877819">將畫面以順時針方向旋轉 90 度</translation>
 <translation id="8433186206711564395">網路設定</translation>
+<translation id="843609873781525167">如果將這項政策設為 True,<ph name="PRODUCT_NAME" /> 一律會在啟動時檢查其是否為預設瀏覽器,並在情況允許時自動登錄。如果將這項政策設為 False,<ph name="PRODUCT_NAME" /> 一律不會檢查其是否為預設瀏覽器,且會停用設定這個選項的使用者控制項。
+
+      如果未設定這項政策,<ph name="PRODUCT_NAME" /> 將允許使用者決定其是否為預設瀏覽器,並在不是預設瀏覽器時允許使用者控制是否要顯示使用者通知。
+
+      注意:<ph name="MS_WIN_NAME" /> 的系統管理員只能在搭載 Windows 7 的電腦上開啟這項設定。如果是較新版本的電腦,系統管理員必須部署「預設應用程式關聯」檔案,將 <ph name="PRODUCT_NAME" /> 做為 <ph name="HTTPS_PROTOCOL" /> 和 <ph name="HTTP_PROTOCOL" /> 通訊協定的處理常式 (也可以一併做為 <ph name="FTP_PROTOCOL" /> 通訊協定和其他檔案格式的處理常式)。請參閱 Chrome 說明文章:https://support.google.com/chrome?p=make_chrome_default_win。</translation>
 <translation id="8445576299806775661">Chrome 會在每次更新主要版本時,為一部分的使用者瀏覽資料建立快照,以便日後需要執行緊急版本復原作業時使用。如果使用者要緊急復原的目標版本有相應快照,系統會復原快照中的資料。這種做法可讓使用者保留書籤和自動填入資料等設定。
 
       如果不設定這項政策,系統會使用預設值 3
@@ -4837,6 +4918,9 @@
 
           如果不設定這項政策,系統在預設狀態下會啟用無障礙功能快速鍵。</translation>
 <translation id="8525526490824335042">Linux 容器</translation>
+<translation id="8537051350735478658">如果將這項政策設為 True,系統會在 <ph name="PRODUCT_NAME" /> 的網址列中啟用搜尋建議功能。如果將這項政策設為 False,系統會停用這類搜尋建議功能。
+
+      如果設定這項政策,使用者將無法變更。如果未設定,系統會先啟用搜尋建議功能,但使用者隨時可以停用。</translation>
 <translation id="8544375438507658205">預設 <ph name="PRODUCT_FRAME_NAME" /> 的 HTML 轉譯器</translation>
 <translation id="8544465954173828789">允許將簡訊從手機同步至 Chromebook。</translation>
 <translation id="8548832052135586762">設定僅限彩色列印、僅限單色列印,或是不限制色彩模式。如未設定這項政策,系統會視為未設限制。</translation>
diff --git a/components/policy/tools/syntax_check_policy_template_json.py b/components/policy/tools/syntax_check_policy_template_json.py
index 0505471..4dbefa7 100755
--- a/components/policy/tools/syntax_check_policy_template_json.py
+++ b/components/policy/tools/syntax_check_policy_template_json.py
@@ -556,7 +556,7 @@
       supported_on = self._CheckContains(policy,
                                          'supported_on',
                                          list,
-                                         optional=True)
+                                         optional=False)
       supported_platforms = []
       if supported_on:
         for s in supported_on:
@@ -592,14 +592,8 @@
                           policy.get('name'))
       self._CheckPlatform(future_on, 'future_on', policy.get('name'))
 
-      if not supported_platforms and not future_on:
-        self._Error(
-            'The policy needs to be supported now or in the future on at '
-            'least one platform.', 'policy', policy.get('name'))
-
-      if supported_on == []:
-        self._Warning("Policy %s: supported_on' is empty." %
-                      (policy.get('name')))
+      #TODO(crbug.com/1091432): Make supported_on optional and check if it's
+      # empty. Also check if both supported_on and future_on are empty.
 
       if future_on == []:
         self._Warning("Policy %s: 'future_on' is empty." % (policy.get('name')))
diff --git a/components/safety_check/safety_check.h b/components/safety_check/safety_check.h
index 8a55e1a..2bd457a 100644
--- a/components/safety_check/safety_check.h
+++ b/components/safety_check/safety_check.h
@@ -20,6 +20,7 @@
   // desktop, Android, and iOS) of the safety check and should be kept in sync
   // with the JS frontend (safety_check_browser_proxy.js) and |SafetyCheck*|
   // metrics enums in enums.xml.
+  // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.safety_check
   enum class SafeBrowsingStatus {
     kChecking = 0,
     kEnabled = 1,
diff --git a/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/AccountManagerFacadeTest.java b/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/AccountManagerFacadeTest.java
index 16f50aa35..00a5ec3d 100644
--- a/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/AccountManagerFacadeTest.java
+++ b/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/AccountManagerFacadeTest.java
@@ -26,13 +26,11 @@
 
 /**
  * Tests for {@link AccountManagerFacade}. See also {@link AccountManagerFacadeRobolectricTest}.
- * TODO(https://crbug.com/1064565): Move this test to Robolectric test set
  */
 @RunWith(BaseJUnit4ClassRunner.class)
 public class AccountManagerFacadeTest {
     private FakeAccountManagerDelegate mDelegate =
-            new FakeAccountManagerDelegate(FakeAccountManagerDelegate.DISABLE_PROFILE_DATA_SOURCE,
-                    FakeAccountManagerDelegate.ENABLE_BLOCK_GET_ACCOUNTS);
+            new FakeAccountManagerDelegate(FakeAccountManagerDelegate.ENABLE_BLOCK_GET_ACCOUNTS);
 
     @Before
     public void setUp() {
diff --git a/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java b/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java
index bf5b7f52..0e0739d 100644
--- a/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java
+++ b/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java
@@ -51,20 +51,10 @@
 public class FakeAccountManagerDelegate implements AccountManagerDelegate {
     private static final String TAG = "FakeAccountManager";
 
-    /** Controls whether FakeAccountManagerDelegate should provide a ProfileDataSource. */
-    @IntDef({DISABLE_PROFILE_DATA_SOURCE, ENABLE_PROFILE_DATA_SOURCE})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface ProfileDataSourceFlag {}
-
-    /** Disables ProfileDataSource: {@link #getProfileDataSource} will return null. */
-    public static final int DISABLE_PROFILE_DATA_SOURCE = 0;
-    /** Use {@link FakeProfileDataSource}. */
-    public static final int ENABLE_PROFILE_DATA_SOURCE = 1;
-
     /** Controls whether FakeAccountManagerDelegate should block get accounts. */
     @IntDef({ENABLE_BLOCK_GET_ACCOUNTS, DISABLE_BLOCK_GET_ACCOUNTS})
     @Retention(RetentionPolicy.SOURCE)
-    public @interface BlockGetAccountsFlag {}
+    @interface BlockGetAccountsFlag {}
 
     /** Disables block get accounts: {@link #getAccountsSync()} will return immediately. */
     public static final int DISABLE_BLOCK_GET_ACCOUNTS = 0;
@@ -73,34 +63,22 @@
 
     private final Set<AccountHolder> mAccounts = new LinkedHashSet<>();
     private final ObserverList<AccountsChangeObserver> mObservers = new ObserverList<>();
-    private boolean mRegisterObserversCalled;
-    private FakeProfileDataSource mFakeProfileDataSource;
     private final CountDownLatch mBlockGetAccounts = new CountDownLatch(1);
 
-    public FakeAccountManagerDelegate(@ProfileDataSourceFlag int profileDataSourceFlag) {
-        this(profileDataSourceFlag, DISABLE_BLOCK_GET_ACCOUNTS);
+    public FakeAccountManagerDelegate() {
+        this(DISABLE_BLOCK_GET_ACCOUNTS);
     }
 
-    public FakeAccountManagerDelegate(@ProfileDataSourceFlag int profileDataSourceFlag,
-            @BlockGetAccountsFlag int blockGetAccountsFlag) {
-        if (profileDataSourceFlag == ENABLE_PROFILE_DATA_SOURCE) {
-            mFakeProfileDataSource = new FakeProfileDataSource();
-        }
+    public FakeAccountManagerDelegate(@BlockGetAccountsFlag int blockGetAccountsFlag) {
         if (blockGetAccountsFlag == DISABLE_BLOCK_GET_ACCOUNTS) {
             mBlockGetAccounts.countDown();
         }
     }
 
-    public void setProfileData(
-            String accountId, @Nullable ProfileDataSource.ProfileData profileData) {
-        assert mFakeProfileDataSource != null : "ProfileDataSource was disabled!";
-        mFakeProfileDataSource.setProfileData(accountId, profileData);
-    }
-
     @Nullable
     @Override
     public ProfileDataSource getProfileDataSource() {
-        return mFakeProfileDataSource;
+        return null;
     }
 
     @Nullable
@@ -115,13 +93,7 @@
     }
 
     @Override
-    public void registerObservers() {
-        mRegisterObserversCalled = true;
-    }
-
-    public boolean isRegisterObserversCalled() {
-        return mRegisterObserversCalled;
-    }
+    public void registerObservers() {}
 
     @Override
     public void addObserver(AccountsChangeObserver observer) {
@@ -145,7 +117,7 @@
         return getAccountsSyncNoThrow();
     }
 
-    public Account[] getAccountsSyncNoThrow() {
+    private Account[] getAccountsSyncNoThrow() {
         ArrayList<Account> result = new ArrayList<>();
         synchronized (mAccounts) {
             for (AccountHolder ah : mAccounts) {
@@ -342,12 +314,4 @@
         }
         return null;
     }
-
-    private AccountHolder getAccountHolder(Account account) {
-        AccountHolder ah = tryGetAccountHolder(account);
-        if (ah == null) {
-            throw new IllegalArgumentException("Can not find AccountHolder for account " + account);
-        }
-        return ah;
-    }
 }
diff --git a/components/signin/core/browser/android/junit/src/org/chromium/components/signin/test/AccountManagerFacadeRobolectricTest.java b/components/signin/core/browser/android/junit/src/org/chromium/components/signin/test/AccountManagerFacadeRobolectricTest.java
index 5621688..356ed1f5 100644
--- a/components/signin/core/browser/android/junit/src/org/chromium/components/signin/test/AccountManagerFacadeRobolectricTest.java
+++ b/components/signin/core/browser/android/junit/src/org/chromium/components/signin/test/AccountManagerFacadeRobolectricTest.java
@@ -4,6 +4,9 @@
 
 package org.chromium.components.signin.test;
 
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 import static org.robolectric.Shadows.shadowOf;
 
 import android.accounts.Account;
@@ -31,7 +34,6 @@
 import org.chromium.components.signin.AccountManagerFacadeImpl;
 import org.chromium.components.signin.AccountUtils;
 import org.chromium.components.signin.ChildAccountStatus;
-import org.chromium.components.signin.ProfileDataSource;
 import org.chromium.components.signin.test.util.AccountHolder;
 import org.chromium.components.signin.test.util.FakeAccountManagerDelegate;
 import org.chromium.testing.local.CustomShadowUserManager;
@@ -49,7 +51,7 @@
         shadows = {CustomShadowAsyncTask.class, CustomShadowUserManager.class})
 public class AccountManagerFacadeRobolectricTest {
     @Rule
-    public UiThreadTestRule mRule = new UiThreadTestRule();
+    public final UiThreadTestRule mRule = new UiThreadTestRule();
 
     private CustomShadowUserManager mShadowUserManager;
     private FakeAccountManagerDelegate mDelegate;
@@ -60,12 +62,8 @@
         Context context = RuntimeEnvironment.application;
         UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mShadowUserManager = (CustomShadowUserManager) shadowOf(userManager);
-
-        mDelegate = new FakeAccountManagerDelegate(
-                FakeAccountManagerDelegate.ENABLE_PROFILE_DATA_SOURCE);
-        Assert.assertFalse(mDelegate.isRegisterObserversCalled());
+        mDelegate = new FakeAccountManagerDelegate();
         mFacade = new AccountManagerFacadeImpl(mDelegate);
-        Assert.assertTrue(mDelegate.isRegisterObserversCalled());
     }
 
     private void setAccountRestrictionPatterns(String... patterns) {
@@ -87,6 +85,15 @@
 
     @Test
     @SmallTest
+    public void testRegisterObserversCalledInConstructor() {
+        FakeAccountManagerDelegate delegate = spy(new FakeAccountManagerDelegate());
+        verify(delegate, never()).registerObservers();
+        AccountManagerFacade accountManagerFacade = new AccountManagerFacadeImpl(delegate);
+        verify(delegate).registerObservers();
+    }
+
+    @Test
+    @SmallTest
     public void testCanonicalAccount() {
         addTestAccount("test@gmail.com");
         List<Account> accounts = mFacade.tryGetGoogleAccounts();
@@ -113,28 +120,6 @@
 
     @Test
     @SmallTest
-    public void testProfileDataSource() throws Throwable {
-        String accountName = "test@gmail.com";
-        addTestAccount(accountName);
-
-        mRule.runOnUiThread(() -> {
-            ProfileDataSource.ProfileData profileData = new ProfileDataSource.ProfileData(
-                    accountName, null, "Test Full Name", "Test Given Name");
-
-            ProfileDataSource profileDataSource = mDelegate.getProfileDataSource();
-            Assert.assertNotNull(profileDataSource);
-            mDelegate.setProfileData(accountName, profileData);
-            Assert.assertArrayEquals(profileDataSource.getProfileDataMap().values().toArray(),
-                    new ProfileDataSource.ProfileData[] {profileData});
-
-            mDelegate.setProfileData(accountName, null);
-            Assert.assertArrayEquals(profileDataSource.getProfileDataMap().values().toArray(),
-                    new ProfileDataSource.ProfileData[0]);
-        });
-    }
-
-    @Test
-    @SmallTest
     public void testGetAccounts() throws AccountManagerDelegateException {
         Assert.assertEquals(ImmutableList.of(), mFacade.getGoogleAccounts());
 
diff --git a/components/strings/components_strings_af.xtb b/components/strings/components_strings_af.xtb
index bf9b385..dc1a99bc 100644
--- a/components/strings/components_strings_af.xtb
+++ b/components/strings/components_strings_af.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Vee soektog uit</translation>
 <translation id="1839551713262164453">Bevestiging van beleidswaardes het misluk met foute</translation>
 <translation id="1842969606798536927">Betaal</translation>
-<translation id="1852694792039666893">Gebruik jou Google-rekening om 'n sterk wagwoord voor te stel</translation>
 <translation id="1871208020102129563">Instaanbediener is gestel om vaste instaanbedieners te gebruik, nie 'n .pac-skrip-URL nie.</translation>
 <translation id="1871284979644508959">Vereiste veld</translation>
 <translation id="1875512691959384712">Google Vorms</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Beste passing</translation>
 <translation id="2691924980723297736">Veiligheidswaarskuwing</translation>
-<translation id="2696268945573510710">Gebruik wagwoorde wat in jou Google-rekening geberg is</translation>
 <translation id="2699302886720511147">Aanvaarde kaarte</translation>
 <translation id="2701514975700770343">Voorkant na onder</translation>
 <translation id="2702801445560668637">Leeslys</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Omval op <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Maak ander programme toe</translation>
 <translation id="2922350208395188000">Bediener se sertifikaat kan nie nagegaan word nie.</translation>
-<translation id="2924027812781652774">Meld aan om wagwoorde te gebruik wat in jou Google-rekening geberg is</translation>
 <translation id="2925673989565098301">Afleweringmetode</translation>
 <translation id="2928905813689894207">Faktureringadres</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> en nog <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> en nog <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_am.xtb b/components/strings/components_strings_am.xtb
index 9905dd9..9eda5be0 100644
--- a/components/strings/components_strings_am.xtb
+++ b/components/strings/components_strings_am.xtb
@@ -220,7 +220,6 @@
 <translation id="1838374766361614909">ፍለጋን ያፅዱ</translation>
 <translation id="1839551713262164453">የመመሪያ እሴቶችን ማረጋገጥ ከስህተቶች ጋር አልተሳካም</translation>
 <translation id="1842969606798536927">ይክፈሉ</translation>
-<translation id="1852694792039666893">ጠንካራ የይለፍ ቃል ለመጠቆም የGoogle መለያዎን ይጠቀሙ</translation>
 <translation id="1871208020102129563">የ.pac ስክሪፕት ዩአርኤል ሳይሆን ተኪ አገልጋዮችን እንዲጠቀም ነው ተኪ የተዋቀረው።</translation>
 <translation id="1871284979644508959">የሚያስፈልግ መስክ</translation>
 <translation id="1875512691959384712">Google ቅጾች</translation>
@@ -405,7 +404,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">ምርጥ መገጣጠም</translation>
 <translation id="2691924980723297736">የደህንነት ማስጠንቀቂያ</translation>
-<translation id="2696268945573510710">በGoogle መለያዎ ላይ የተከማቹ የይለፍ ቃላትን ይጠቀሙ</translation>
 <translation id="2699302886720511147">ተቀባይነት ያላቸው ካርዶች</translation>
 <translation id="2701514975700770343">ፊት ወደ ታች</translation>
 <translation id="2702801445560668637">የንባብ ዝርዝር</translation>
@@ -452,7 +450,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" /> ላይ ስንክል</translation>
 <translation id="2916038427272391327">ሌሎች ፕሮግራሞችን ይዝጉ</translation>
 <translation id="2922350208395188000">የአገልጋይ እውቅና ማረጋገጫ ሊረጋገጥ አልቻለም።</translation>
-<translation id="2924027812781652774">በእርስዎ Google መለያ ውስጥ የተከማቹ የይለፍ ቃላትን ለመጠቀም ይግቡ</translation>
 <translation id="2925673989565098301">የማድረሻ ስልት</translation>
 <translation id="2928905813689894207">ክፍያ የሚጠየቅበት አድራሻ</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> እና <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ተጨማሪ}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> እና <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ተጨማሪ}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> እና <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ተጨማሪ}}</translation>
diff --git a/components/strings/components_strings_ar.xtb b/components/strings/components_strings_ar.xtb
index a3778bb..37b9606 100644
--- a/components/strings/components_strings_ar.xtb
+++ b/components/strings/components_strings_ar.xtb
@@ -205,10 +205,10 @@
 <translation id="1753706481035618306">رقم الصفحة</translation>
 <translation id="1763864636252898013">هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />؛ بل إنه شهادة أمان غير موثوقة من خلال نظام تشغيل جهازك. وربما يكون السبب في ذلك خطأ في التكوين أو مهاجمًا يعترض الاتصال.</translation>
 <translation id="1768211456781949159">‏<ph name="BEGIN_LINK" />تجربة تشغيل بيانات التشخيص لشبكة Windows<ph name="END_LINK" />.</translation>
-<translation id="1772163372082567643">لقد أعَدّ الخادم الذي تنتقل إليه، <ph name="ORIGIN" />، عنوانًا يتطلب فيه
-    أن يتم تطبيق سياسة المصدر على جميع الطلبات المقدَّمة إليه. ولكن
-    العنوان غير صالح، وبالتالي يُمنع المتصفِّح من توصيل
-    طلبك إلى الموقع الإلكتروني <ph name="SITE" />. ويمكن استخدام سياسات المصدر من خلال
+<translation id="1772163372082567643">إنّ خادم <ph name="ORIGIN" /> الذي تنتقل إليه أعدّ عنوانًا يتطلّب
+    تطبيق سياسة المصدر على جميع الطلبات المقدّمة إليه، ولكن
+    العنوان غير صالح، مما يمنع المتصفِّح من إكمال
+    طلبك ذي الصلة بالموقع الإلكتروني <ph name="SITE" />. ويمكن استخدام سياسات المصدر من خلال
     عوامل تشغيل المواقع الإلكترونية لضبط الأمان والخصائص الأخرى لموقع إلكتروني.</translation>
 <translation id="1778646502362731194">JIS B0</translation>
 <translation id="1783075131180517613">يُرجى تحديث عبارة مرور المزامنة.</translation>
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">محو البحث</translation>
 <translation id="1839551713262164453">لقد تعذّر التحقق من قيم السياسة مع ظهور أخطاء.</translation>
 <translation id="1842969606798536927">الدفع</translation>
-<translation id="1852694792039666893">‏استخدام حسابك على Google لاقتراح كلمة مرور قوية</translation>
 <translation id="1871208020102129563">‏تم تعيين الخادم الوكيل لاستخدام الخوادم الوكيلة الثابتة وليس عنوان URL لنص برمجي pac.</translation>
 <translation id="1871284979644508959">حقل مطلوب</translation>
 <translation id="1875512691959384712">‏نماذج Google</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">أفضل حجم</translation>
 <translation id="2691924980723297736">تحذير متعلق بالأمان</translation>
-<translation id="2696268945573510710">‏استخدِم كلمات المرور المُخزّنة في حسابك على Google</translation>
 <translation id="2699302886720511147">البطاقات المقبولة</translation>
 <translation id="2701514975700770343">الوجه للأسفل</translation>
 <translation id="2702801445560668637">قائمة القراءة</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">مُعطّل منذ <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">إغلاق البرامج الأخرى</translation>
 <translation id="2922350208395188000">لا يمكن التحقق من شهادة الخادم.</translation>
-<translation id="2924027812781652774">‏يُرجى تسجيل الدخول لاستخدام كلمات المرور المُخزّنة في حسابك على Google.</translation>
 <translation id="2925673989565098301">طريقة التسليم</translation>
 <translation id="2928905813689894207">عنوان إرسال الفواتير</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> وعنوان <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> آخر}two{<ph name="SHIPPING_ADDRESS_PREVIEW" /> وعنوانان (<ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />) آخران}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> و<ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> عناوين أخرى}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> و<ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> عنوانًا آخر}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> و<ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> عنوان آخر}}</translation>
@@ -757,11 +754,11 @@
 <translation id="4194250254487269611">يتعذّر حفظ بطاقتك الآن.</translation>
 <translation id="4196861286325780578">إ&amp;عادة النقل</translation>
 <translation id="4203896806696719780"><ph name="BEGIN_LINK" />التحقق من عمليات تهيئة الجدار الناري وبرامج مكافحة الفيروسات<ph name="END_LINK" /></translation>
-<translation id="4209166701302774460">لقد طلب الخادم الذي تنتقل إليه، <ph name="ORIGIN" />، تطبيق
-    سياسة المصدر على جميع الطلبات المقدَّمة إليه. ولكن تعذّر الآن
-    عرض سياسة تمنع المتصفِّح من توصيل طلبك
-    إلى الموقع الإلكتروني <ph name="SITE" />. ويمكن استخدام سياسات المصدر من خلال
-    عوامل تشغيل الموقع الإلكتروني لضبط الأمان والخصائص الأخرى للموقع الإلكتروني.</translation>
+<translation id="4209166701302774460">إن خادم <ph name="ORIGIN" /> الذي تنتقل إليه قد طلب تطبيق
+    سياسة المصدر على جميع الطلبات المقدَّمة إليه، ولكن تعذّر الآن
+    عرض سياسة، مما يمنع المتصفِّح من إكمال طلبك
+    ذي الصلة بالموقع الإلكتروني <ph name="SITE" />. ويمكن استخدام سياسات المصدر من خلال
+    عوامل تشغيل الموقع الإلكتروني لضبط الأمان والخصائص الأخرى لموقع إلكتروني.</translation>
 <translation id="421066178035138955">استخدام أجهزة الواقع الافتراضي وبياناتها</translation>
 <translation id="4214357935346142455">الملف الشخصي في شاشة تسجيل الدخول</translation>
 <translation id="4215751373031079683">‏7x9 (مغلف)</translation>
diff --git a/components/strings/components_strings_as.xtb b/components/strings/components_strings_as.xtb
index c15f7ff..0e65c1a 100644
--- a/components/strings/components_strings_as.xtb
+++ b/components/strings/components_strings_as.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">সন্ধান কৰা বস্তুবোৰ মচক</translation>
 <translation id="1839551713262164453">নীতিৰ মান মান্যতাকৰণ কৰোঁতে আসোঁৱাহ হৈছে</translation>
 <translation id="1842969606798536927">পৰিশোধ কৰক</translation>
-<translation id="1852694792039666893">এটা শক্তিশালী পাছৱৰ্ডৰ পৰামৰ্শ আগবঢ়াবলৈ আপোনাৰ Google একাউণ্টটো ব্যৱহাৰ কৰক</translation>
 <translation id="1871208020102129563">প্ৰক্সিয়ে কোনো .pac স্ক্ৰিপ্টৰ URLৰ সলনি স্থিৰ প্ৰ'ক্সী ছার্ভাৰ ব্যৱহাৰ কৰিবলৈ ছেট কৰা হৈছে।</translation>
 <translation id="1871284979644508959">বাধ্যতামূলক ক্ষেত্ৰ</translation>
 <translation id="1875512691959384712">Google Forms</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">১১x১২</translation>
 <translation id="2687555958734450033">উত্তম মিল</translation>
 <translation id="2691924980723297736">সুৰক্ষা সম্পর্কীয় সতর্কবার্তা</translation>
-<translation id="2696268945573510710">আপোনাৰ Google একাউণ্টত ষ্ট’ৰ কৰি থোৱা পাছৱৰ্ডসমূহ ব্যৱহাৰ কৰক</translation>
 <translation id="2699302886720511147">গ্ৰহণ কৰা কাৰ্ডসমূহ</translation>
 <translation id="2701514975700770343">তলমুখীয়াকৈ</translation>
 <translation id="2702801445560668637">পঢ়াৰ সূচী</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" />ত হোৱা ক্ৰেশ্ব</translation>
 <translation id="2916038427272391327">অন্য প্ৰ’গ্ৰেমসমূহ বন্ধ কৰক</translation>
 <translation id="2922350208395188000">ছাৰ্ভাৰৰ প্ৰমাণপত্ৰ পৰীক্ষা কৰিব নোৱাৰি।</translation>
-<translation id="2924027812781652774">আপোনাৰ Google একাউণ্টত ষ্ট’ৰ হৈ থকা পাছৱৰ্ডসমূহ ব্যৱহাৰ কৰিবলৈ ছাইন ইন কৰক</translation>
 <translation id="2925673989565098301">ডেলিভাৰীৰ পদ্ধতি</translation>
 <translation id="2928905813689894207">বিলৰ ঠিকনা</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> আৰু <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />টা অধিক}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> আৰু <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />টা অধিক}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> আৰু <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />টা অধিক}}</translation>
diff --git a/components/strings/components_strings_az.xtb b/components/strings/components_strings_az.xtb
index 13ef1b3..8a31415 100644
--- a/components/strings/components_strings_az.xtb
+++ b/components/strings/components_strings_az.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Axtarışı təmizləyin</translation>
 <translation id="1839551713262164453">Siyasət dəyərlərinin doğrulanması xəta səbəbilə alınmadı</translation>
 <translation id="1842969606798536927">Ödəniş</translation>
-<translation id="1852694792039666893">Güclü parol təklif etmək üçün Google Hesabınızdan istifadə edin</translation>
 <translation id="1871208020102129563">Proksi .pac skript URL deyil sabit proksi serverlər istifadə etmək üçün ayarlanıb.</translation>
 <translation id="1871284979644508959">Tələb olunan sahə</translation>
 <translation id="1875512691959384712">Google Formalar</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Ən uyğun</translation>
 <translation id="2691924980723297736">Təhlükəsizlik xəbərdarlığı</translation>
-<translation id="2696268945573510710">Google Hesabınızda saxlanılan parolları istifadə edin</translation>
 <translation id="2699302886720511147">Qəbul edilən Kartlar</translation>
 <translation id="2701514975700770343">Üzü aşağı</translation>
 <translation id="2702801445560668637">Siyahı oxunur</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Xəta tarixi: <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Digər proqramları bağlayın</translation>
 <translation id="2922350208395188000">Server sertifikatı yoxlana bilmədi.</translation>
-<translation id="2924027812781652774">Google Hesabınızda saxlanılan parolları istifadə etmək üçün daxil olun</translation>
 <translation id="2925673989565098301">Çatdırılma Üsulu</translation>
 <translation id="2928905813689894207">Faktura Ünvanı</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> və daha <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> və daha <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_be.xtb b/components/strings/components_strings_be.xtb
index 45e2ea3..433a954 100644
--- a/components/strings/components_strings_be.xtb
+++ b/components/strings/components_strings_be.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Ачысціць поле пошуку</translation>
 <translation id="1839551713262164453">Пра праверцы значэнняў палітыкі адбыліся памылкі</translation>
 <translation id="1842969606798536927">Аплаціць</translation>
-<translation id="1852694792039666893">Стварыць надзейны пароль ва Уліковым запісе Google</translation>
 <translation id="1871208020102129563">Канфігурацыяй проксі зададзена выкарыстоўваць фіксаваныя проксі-серверы, а не URL-адрас сцэнарыя .pac.</translation>
 <translation id="1871284979644508959">Абавязковае поле</translation>
 <translation id="1875512691959384712">Формы Google</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Аптымальны памер</translation>
 <translation id="2691924980723297736">Папярэджанне сістэмы бяспекі</translation>
-<translation id="2696268945573510710">Выкарыстоўваць паролі, захаваныя ва Уліковым запісе Google</translation>
 <translation id="2699302886720511147">Якія карткі прымаюцца</translation>
 <translation id="2701514975700770343">Рабочым бокам уніз</translation>
 <translation id="2702801445560668637">Спіс чытання</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Час збою: <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Закрыйце іншыя праграмы.</translation>
 <translation id="2922350208395188000">Немагчыма праверыць сертыфікат сервера.</translation>
-<translation id="2924027812781652774">Каб выкарыстоўваць захаваныя ва Уліковым запісе Google паролі, увайдзіце ў яго</translation>
 <translation id="2925673989565098301">Спосаб дастаўкі</translation>
 <translation id="2928905813689894207">Адрас для выстаўлення рахункаў</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> і яшчэ <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> і яшчэ <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> і яшчэ <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> і яшчэ <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> і яшчэ <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_bg.xtb b/components/strings/components_strings_bg.xtb
index a0409053..fb247396 100644
--- a/components/strings/components_strings_bg.xtb
+++ b/components/strings/components_strings_bg.xtb
@@ -222,7 +222,6 @@
 <translation id="1838374766361614909">Изчистване на търсенето</translation>
 <translation id="1839551713262164453">Проверката на стойностите на правилата не бе успешна – възникнаха грешки</translation>
 <translation id="1842969606798536927">Плащане</translation>
-<translation id="1852694792039666893">Използване на профила ви в Google за предлагане на надеждна парола</translation>
 <translation id="1871208020102129563">За прокси сървъра е зададено да използва фиксирани прокси сървъри, а не URL адрес на скрипт във формат .pac.</translation>
 <translation id="1871284979644508959">Задължително поле</translation>
 <translation id="1875512691959384712">Google Формуляри</translation>
@@ -407,7 +406,6 @@
 <translation id="2684561033061424857">11 x 12</translation>
 <translation id="2687555958734450033">Напасване</translation>
 <translation id="2691924980723297736">Предупреждение за безопасност</translation>
-<translation id="2696268945573510710">Използване на паролите, съхранявани в профила ви в Google</translation>
 <translation id="2699302886720511147">Приемани карти</translation>
 <translation id="2701514975700770343">С отпечатаната страна надолу</translation>
 <translation id="2702801445560668637">Списък за четене</translation>
@@ -454,7 +452,6 @@
 <translation id="2915068235268646559">Срив от <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Затворете другите програми.</translation>
 <translation id="2922350208395188000">Сертификатът на сървъра не може да бъде проверен.</translation>
-<translation id="2924027812781652774">Влезте в профила си в Google, за да използвате съхраняваните в него пароли</translation>
 <translation id="2925673989565098301">Начин на бърза доставка</translation>
 <translation id="2928905813689894207">Адрес за фактуриране</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и още <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и още <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_bn.xtb b/components/strings/components_strings_bn.xtb
index d896050e..881a337 100644
--- a/components/strings/components_strings_bn.xtb
+++ b/components/strings/components_strings_bn.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">সার্চ সাফ করুন</translation>
 <translation id="1839551713262164453">নীতির মূল্য যাচাইকরণে সমস্যা হওয়ার জন্য যাচাই করা যায়নি</translation>
 <translation id="1842969606798536927">পেমেন্ট করুন</translation>
-<translation id="1852694792039666893">আপনার Google অ্যাকাউন্ট ব্যবহার করে একটি শক্তিশালী পাসওয়ার্ড সাজেস্ট করুন</translation>
 <translation id="1871208020102129563">
 প্রক্সি স্থির প্রক্সি সার্ভারগুলি ব্যবহার করতে সেট করা আছে কোনো .pac স্ক্রিপ্ট URL নয়৷</translation>
 <translation id="1871284979644508959">আবশ্যক ক্ষেত্র</translation>
@@ -410,7 +409,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">সবচেয়ে মানানসই</translation>
 <translation id="2691924980723297736">নিরাপত্তা সম্পর্কিত সতর্কতা</translation>
-<translation id="2696268945573510710">আপনার Google অ্যাকাউন্টে স্টোর করা পাসওয়ার্ড ব্যবহার করুন</translation>
 <translation id="2699302886720511147">এই কার্ডগুলি গ্রহণ করা হয়</translation>
 <translation id="2701514975700770343">সামনের দিক নিচে</translation>
 <translation id="2702801445560668637">পড়ার তালিকা</translation>
@@ -459,7 +457,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" />-এ হওয়া ক্র্যাশ</translation>
 <translation id="2916038427272391327">অন্যান্য প্রোগ্রামগুলি বন্ধ করুন</translation>
 <translation id="2922350208395188000">সার্ভারের সার্টিফিকেট চেক করা যাবে না৷</translation>
-<translation id="2924027812781652774">আপনার Google অ্যাকাউন্টে স্টোর করা পাসওয়ার্ড ব্যবহার করতে আবার সাইন-ইন করুন</translation>
 <translation id="2925673989565098301">ডেলিভারির পদ্ধতি</translation>
 <translation id="2928905813689894207">বিলিংয়ের ঠিকানা</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> এবং আরও <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />টি}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> এবং আরও <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />টি}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> এবং আরও <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />টি}}</translation>
diff --git a/components/strings/components_strings_bs.xtb b/components/strings/components_strings_bs.xtb
index 7accb85..f91b627 100644
--- a/components/strings/components_strings_bs.xtb
+++ b/components/strings/components_strings_bs.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Obriši pretraživanje</translation>
 <translation id="1839551713262164453">Potvrda vrijednosti pravila nije uspjela i ima grešaka</translation>
 <translation id="1842969606798536927">Plati</translation>
-<translation id="1852694792039666893">Koristite svoj Google račun da predložite jaku lozinku</translation>
 <translation id="1871208020102129563">Proksi server je postavljen za korištenje fiksnih proksi servera, a ne URL .pac skripte.</translation>
 <translation id="1871284979644508959">Obavezno polje</translation>
 <translation id="1875512691959384712">Google Forms</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11 x 12</translation>
 <translation id="2687555958734450033">Najpogodniji format</translation>
 <translation id="2691924980723297736">Sigurnosno upozorenje</translation>
-<translation id="2696268945573510710">Koristite lozinke pohranjene na Google računu</translation>
 <translation id="2699302886720511147">Prihvaćene kartice</translation>
 <translation id="2701514975700770343">Odštampana strana prema dolje</translation>
 <translation id="2702801445560668637">Lista za čitanje</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Pad aplikacije od <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Zatvorite druge programe</translation>
 <translation id="2922350208395188000">Certifikat poslužitelja nije moguće provjeriti.</translation>
-<translation id="2924027812781652774">Prijavite se da koristite lozinke pohranjene na Google računu</translation>
 <translation id="2925673989565098301">Način dostave</translation>
 <translation id="2928905813689894207">Adresa za naplatu</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_ca.xtb b/components/strings/components_strings_ca.xtb
index 988596c..829ccf1 100644
--- a/components/strings/components_strings_ca.xtb
+++ b/components/strings/components_strings_ca.xtb
@@ -220,7 +220,6 @@
 <translation id="1838374766361614909">Esborra la cerca</translation>
 <translation id="1839551713262164453">S'han produït errors a la validació dels valors de la política</translation>
 <translation id="1842969606798536927">Paga</translation>
-<translation id="1852694792039666893">Utilitza el teu Compte de Google per suggerir una contrasenya segura</translation>
 <translation id="1871208020102129563">El servidor intermediari està configurat perquè utilitzi servidors intermediaris fixos, en lloc d'un URL d'script .pac.</translation>
 <translation id="1871284979644508959">Camp obligatori</translation>
 <translation id="1875512691959384712">Formularis de Google</translation>
@@ -405,7 +404,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Mida òptima</translation>
 <translation id="2691924980723297736">Advertiment de seguretat</translation>
-<translation id="2696268945573510710">Utilitza les contrasenyes emmagatzemades al teu Compte de Google</translation>
 <translation id="2699302886720511147">Targetes acceptades</translation>
 <translation id="2701514975700770343">Cara avall</translation>
 <translation id="2702801445560668637">Llista de lectura</translation>
@@ -452,7 +450,6 @@
 <translation id="2915068235268646559">Inici del bloqueig: <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Tanca altres programes</translation>
 <translation id="2922350208395188000">No es pot comprovar el certificat del servidor.</translation>
-<translation id="2924027812781652774">Inicia la sessió per utilitzar les contrasenyes emmagatzemades al teu Compte de Google</translation>
 <translation id="2925673989565098301">Mètode d'entrega</translation>
 <translation id="2928905813689894207">Adreça de facturació</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> més}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> més}}</translation>
diff --git a/components/strings/components_strings_cs.xtb b/components/strings/components_strings_cs.xtb
index ffd31d00..c5eb7ce 100644
--- a/components/strings/components_strings_cs.xtb
+++ b/components/strings/components_strings_cs.xtb
@@ -178,6 +178,7 @@
 <translation id="1671391448414634642">Stránky v jazyce <ph name="SOURCE_LANGUAGE" /> se od teď budou překládat do jazyka <ph name="TARGET_LANGUAGE" />.</translation>
 <translation id="1676269943528358898">Web <ph name="SITE" /> vaše informace běžně chrání šifrováním. Když se prohlížeč Chrome k webu <ph name="SITE" /> pokusil připojit tentokrát, web vrátil neobvyklé a nesprávné identifikační údaje. K tomuto problému může dojít, pokud se za web <ph name="SITE" /> pokouší vydávat nějaký útočník nebo pokud bylo připojení přerušeno přihlašovací obrazovkou sítě Wi-Fi. Vaše informace jsou i nadále v bezpečí, protože prohlížeč Google Chrome připojení přerušil dříve, než došlo k odeslání jakýchkoliv dat.</translation>
 <translation id="1682696192498422849">Krátkou hranou napřed</translation>
+<translation id="168693727862418163">Hodnotu zásady se nepodařilo ověřit proti schématu a bude ignorována.</translation>
 <translation id="168841957122794586">Certifikát serveru obsahuje slabý kryptografický klíč.</translation>
 <translation id="1697532407822776718">Vše je nastaveno!</translation>
 <translation id="1703835215927279855">Letter</translation>
@@ -220,7 +221,6 @@
 <translation id="1838374766361614909">Vymazat vyhledávání</translation>
 <translation id="1839551713262164453">Ověření hodnot zásad selhalo s chybami</translation>
 <translation id="1842969606798536927">Zaplatit</translation>
-<translation id="1852694792039666893">Navrhnout silné heslo pomocí účtu Google</translation>
 <translation id="1871208020102129563">Proxy je nastaveno na používání pevně daných serverů proxy, nikoliv adresy URL skriptu PAC.</translation>
 <translation id="1871284979644508959">Povinné pole</translation>
 <translation id="1875512691959384712">Formuláře Google</translation>
@@ -405,7 +405,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Přizpůsobit</translation>
 <translation id="2691924980723297736">Bezpečnostní upozornění</translation>
-<translation id="2696268945573510710">Použít hesla uložená v účtu Google</translation>
 <translation id="2699302886720511147">Přijímané karty</translation>
 <translation id="2701514975700770343">Lícem dolů</translation>
 <translation id="2702801445560668637">Seznam četby</translation>
@@ -452,7 +451,6 @@
 <translation id="2915068235268646559">Selhání z: <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Zavřete ostatní programy</translation>
 <translation id="2922350208395188000">Certifikát serveru nelze zkontrolovat.</translation>
-<translation id="2924027812781652774">Chcete-li používat hesla uložená v účtu Google, přihlaste se</translation>
 <translation id="2925673989565098301">Způsob doručení</translation>
 <translation id="2928905813689894207">Fakturační adresa</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> další}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> další}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> další}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> dalších}}</translation>
diff --git a/components/strings/components_strings_da.xtb b/components/strings/components_strings_da.xtb
index b07b353..96ca17f 100644
--- a/components/strings/components_strings_da.xtb
+++ b/components/strings/components_strings_da.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Ryd søgning</translation>
 <translation id="1839551713262164453">Validering af politikværdier mislykkedes med fejl</translation>
 <translation id="1842969606798536927">Betal</translation>
-<translation id="1852694792039666893">Brug din Google-konto til at oprette en stærk adgangskode</translation>
 <translation id="1871208020102129563">Proxy er indstillet til at bruge faste proxyservere, ikke webadresser til .pac-scripts.</translation>
 <translation id="1871284979644508959">Skal udfyldes</translation>
 <translation id="1875512691959384712">Google Analyse</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Bedste format</translation>
 <translation id="2691924980723297736">Sikkerhedsadvarsel</translation>
-<translation id="2696268945573510710">Brug adgangskoder, der er gemt på din Google-konto</translation>
 <translation id="2699302886720511147">Accepterede kort</translation>
 <translation id="2701514975700770343">Forside nedad</translation>
 <translation id="2702801445560668637">Læseliste</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Nedbrud fra <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Luk andre programmer</translation>
 <translation id="2922350208395188000">Serverens certifikat kan ikke kontrolleres.</translation>
-<translation id="2924027812781652774">Log ind for at bruge de adgangskoder, du har gemt på din Google-konto</translation>
 <translation id="2925673989565098301">Leveringsmetode</translation>
 <translation id="2928905813689894207">Faktureringsadresse</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> anden}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> anden}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> andre}}</translation>
diff --git a/components/strings/components_strings_de.xtb b/components/strings/components_strings_de.xtb
index 925c0ef..3156093 100644
--- a/components/strings/components_strings_de.xtb
+++ b/components/strings/components_strings_de.xtb
@@ -220,7 +220,6 @@
 <translation id="1838374766361614909">Suche löschen</translation>
 <translation id="1839551713262164453">Die Validierung der Richtlinienwerte hat Fehler ergeben und ist fehlgeschlagen</translation>
 <translation id="1842969606798536927">Bezahlen</translation>
-<translation id="1852694792039666893">Google-Konto verwenden, um ein starkes Passwort vorzuschlagen</translation>
 <translation id="1871208020102129563">Der Proxy ist zur Verwendung von festen Proxyservern konfiguriert, nicht zur Verwendung einer PAC-Skript-URL.</translation>
 <translation id="1871284979644508959">Pflichtfeld</translation>
 <translation id="1875512691959384712">Google Formulare</translation>
@@ -405,7 +404,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Beste Anordnung</translation>
 <translation id="2691924980723297736">Sicherheitswarnung</translation>
-<translation id="2696268945573510710">In meinem Google-Konto gespeicherte Passwörter verwenden</translation>
 <translation id="2699302886720511147">Akzeptierte Karten</translation>
 <translation id="2701514975700770343">Vorderseite nach unten</translation>
 <translation id="2702801445560668637">Leseliste</translation>
@@ -452,7 +450,6 @@
 <translation id="2915068235268646559">Absturz vom <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Andere Programme schließen</translation>
 <translation id="2922350208395188000">Das Serverzertifikat kann nicht überprüft werden.</translation>
-<translation id="2924027812781652774">Melden Sie sich an, um die in Ihrem Google-Konto gespeicherten Passwörter zu verwenden</translation>
 <translation id="2925673989565098301">Lieferoption</translation>
 <translation id="2928905813689894207">Rechnungsadresse</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> und <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> weitere}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> und <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> weitere}}</translation>
diff --git a/components/strings/components_strings_el.xtb b/components/strings/components_strings_el.xtb
index f5a68b9..6083548 100644
--- a/components/strings/components_strings_el.xtb
+++ b/components/strings/components_strings_el.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Διαγραφή αναζητήσεων</translation>
 <translation id="1839551713262164453">Η επικύρωση των τιμών πολιτικής απέτυχε αφού παρουσίασε σφάλματα</translation>
 <translation id="1842969606798536927">Πληρωμή</translation>
-<translation id="1852694792039666893">Χρησιμοποιήστε τον Λογαριασμό σας Google για προτάσεις ισχυρών κωδικών πρόσβασης</translation>
 <translation id="1871208020102129563">Ο διακομιστής μεσολάβησης έχει ρυθμιστεί να χρησιμοποιεί διακομιστές μεσολάβησης και όχι μια διεύθυνση URL σεναρίου .pac.</translation>
 <translation id="1871284979644508959">Απαιτούμενο πεδίο</translation>
 <translation id="1875512691959384712">Φόρμες Google</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Βέλτιστη προσαρμογή</translation>
 <translation id="2691924980723297736">Προειδοποίηση ασφαλείας</translation>
-<translation id="2696268945573510710">Χρησιμοποιήστε τους κωδικούς πρόσβασης που είναι αποθηκευμένοι στον Λογαριασμό σας Google</translation>
 <translation id="2699302886720511147">Αποδεκτές κάρτες</translation>
 <translation id="2701514975700770343">Πρόσοψη προς τα κάτω</translation>
 <translation id="2702801445560668637">Λίστα ανάγνωσης</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Σφάλμα από τις <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Κλείστε τα άλλα προγράμματα</translation>
 <translation id="2922350208395188000">Δεν είναι δυνατός ο έλεγχος του πιστοποιητικού του διακομιστή.</translation>
-<translation id="2924027812781652774">Συνδεθείτε, για να χρησιμοποιήσετε κωδικούς πρόσβασης που είναι αποθηκευμένοι στον Λογαριασμό σας Google.</translation>
 <translation id="2925673989565098301">Τρόπος προβολής</translation>
 <translation id="2928905813689894207">Διεύθυνση χρέωσης</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> και <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ακόμη}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> και <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ακόμη}}</translation>
diff --git a/components/strings/components_strings_en-GB.xtb b/components/strings/components_strings_en-GB.xtb
index ee6fcbf..e6856d5f 100644
--- a/components/strings/components_strings_en-GB.xtb
+++ b/components/strings/components_strings_en-GB.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Clear search</translation>
 <translation id="1839551713262164453">Validation of policy values has failed with errors</translation>
 <translation id="1842969606798536927">Pay</translation>
-<translation id="1852694792039666893">Use your Google Account to suggest a strong password</translation>
 <translation id="1871208020102129563">Proxy is set to use fixed proxy servers, not a .pac script URL.</translation>
 <translation id="1871284979644508959">Required field</translation>
 <translation id="1875512691959384712">Google Forms</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Best fit</translation>
 <translation id="2691924980723297736">Safety warning</translation>
-<translation id="2696268945573510710">Use passwords stored in your Google Account</translation>
 <translation id="2699302886720511147">Accepted Cards</translation>
 <translation id="2701514975700770343">Face down</translation>
 <translation id="2702801445560668637">Reading List</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Crash from <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Close other programmes</translation>
 <translation id="2922350208395188000">Server's certificate cannot be checked.</translation>
-<translation id="2924027812781652774">Sign in to use passwords stored in your Google Account</translation>
 <translation id="2925673989565098301">Delivery Method</translation>
 <translation id="2928905813689894207">Billing Address</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> and <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> more}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> and <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> more}}</translation>
diff --git a/components/strings/components_strings_es-419.xtb b/components/strings/components_strings_es-419.xtb
index 6e734e50..bbd669f3 100644
--- a/components/strings/components_strings_es-419.xtb
+++ b/components/strings/components_strings_es-419.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Borrar la búsqueda</translation>
 <translation id="1839551713262164453">Se produjeron errores en la validación de los valores de la política</translation>
 <translation id="1842969606798536927">Pagar</translation>
-<translation id="1852694792039666893">Usar tu Cuenta de Google para generar una contraseña segura</translation>
 <translation id="1871208020102129563">El proxy está configurado para usar servidores proxy fijos, no una URL de script .pac.</translation>
 <translation id="1871284979644508959">Campo obligatorio</translation>
 <translation id="1875512691959384712">Formularios de Google</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Ajustar tamaño</translation>
 <translation id="2691924980723297736">Advertencia de seguridad</translation>
-<translation id="2696268945573510710">Usar las contraseñas almacenadas en tu Cuenta de Google</translation>
 <translation id="2699302886720511147">Tarjetas aceptadas</translation>
 <translation id="2701514975700770343">Hacia abajo</translation>
 <translation id="2702801445560668637">Lista de lectura</translation>
@@ -456,7 +454,6 @@
 <translation id="2915068235268646559">Falla desde el <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Cierra los demás programas.</translation>
 <translation id="2922350208395188000">No se puede comprobar el certificado del servidor.</translation>
-<translation id="2924027812781652774">Accede a tu Cuenta de Google para usar las contraseñas almacenadas allí</translation>
 <translation id="2925673989565098301">Método de entrega</translation>
 <translation id="2928905813689894207">Dirección de facturación</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> más}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> más}}</translation>
diff --git a/components/strings/components_strings_es.xtb b/components/strings/components_strings_es.xtb
index 6fc16a1..021e276 100644
--- a/components/strings/components_strings_es.xtb
+++ b/components/strings/components_strings_es.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Borrar búsqueda</translation>
 <translation id="1839551713262164453">No se ha podido hacer la validación de los valores de la política porque se han producido errores</translation>
 <translation id="1842969606798536927">Pagar</translation>
-<translation id="1852694792039666893">Utilizar tu cuenta de Google para que te sugiera una contraseña segura</translation>
 <translation id="1871208020102129563">Se ha configurado el proxy de forma que use servidores proxy fijos, en lugar de una URL de secuencia de comandos .pac.</translation>
 <translation id="1871284979644508959">Campo obligatorio</translation>
 <translation id="1875512691959384712">Formularios de Google</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Mejor ajuste</translation>
 <translation id="2691924980723297736">Advertencia de seguridad</translation>
-<translation id="2696268945573510710">Usar contraseñas almacenadas en tu cuenta de Google</translation>
 <translation id="2699302886720511147">Tarjetas aceptadas</translation>
 <translation id="2701514975700770343">Boca abajo</translation>
 <translation id="2702801445560668637">Lista de lectura</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Fallo registrado el <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Cierra otros programas</translation>
 <translation id="2922350208395188000">No es posible comprobar el certificado del servidor.</translation>
-<translation id="2924027812781652774">Inicia sesión para usar las contraseñas almacenadas en tu cuenta de Google</translation>
 <translation id="2925673989565098301">Método de entrega</translation>
 <translation id="2928905813689894207">Dirección de facturación</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> más}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> más}}</translation>
diff --git a/components/strings/components_strings_et.xtb b/components/strings/components_strings_et.xtb
index 29818cd..b672eee 100644
--- a/components/strings/components_strings_et.xtb
+++ b/components/strings/components_strings_et.xtb
@@ -223,7 +223,6 @@
 <translation id="1838374766361614909">Otsingu kustutamine</translation>
 <translation id="1839551713262164453">Reegli väärtuste valideerimine nurjus ja selle käigus ilmnesid vead</translation>
 <translation id="1842969606798536927">Maksmine</translation>
-<translation id="1852694792039666893">Kasutage tugeva parooli soovitamiseks oma Google'i kontot</translation>
 <translation id="1871208020102129563">Puhverserver on seatud kasutama fikseeritud puhverservereid, mitte pac-skripti URL-i.</translation>
 <translation id="1871284979644508959">Kohustuslik väli</translation>
 <translation id="1875512691959384712">Google'i vormid</translation>
@@ -408,7 +407,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Parim sobivus</translation>
 <translation id="2691924980723297736">Ohutusalane hoiatus</translation>
-<translation id="2696268945573510710">Kasutage oma Google'i kontole salvestatud paroole</translation>
 <translation id="2699302886720511147">Aktsepteeritavad kaardid</translation>
 <translation id="2701514975700770343">Esikülg allapoole</translation>
 <translation id="2702801445560668637">Lugemisloend</translation>
@@ -457,7 +455,6 @@
 <translation id="2915068235268646559">Kokkujooksmine – <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Sulgege muud programmid</translation>
 <translation id="2922350208395188000">Serveri sertifikaati ei saa kontrollida.</translation>
-<translation id="2924027812781652774">Logige sisse, et kasutada oma Google'i kontole salvestatud paroole</translation>
 <translation id="2925673989565098301">Kohaletoimetamisviis</translation>
 <translation id="2928905813689894207">Arveldusaadress</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ja veel <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ja veel <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_eu.xtb b/components/strings/components_strings_eu.xtb
index 42c5c5da..907f6d5 100644
--- a/components/strings/components_strings_eu.xtb
+++ b/components/strings/components_strings_eu.xtb
@@ -205,7 +205,7 @@
 <translation id="1753706481035618306">Orri-zenbakia</translation>
 <translation id="1763864636252898013">Zerbitzari honek ezin izan du egiaztatu <ph name="DOMAIN" /> domeinua denik. Zure gailuaren sistema eragilea ez da bere segurtasun-ziurtagiriaz fidatzen. Baliteke gaizki konfiguratuta dagoelako izatea edo erasotzaile batek zure konexioa atzeman duelako izatea.</translation>
 <translation id="1768211456781949159"><ph name="BEGIN_LINK" />Abiarazi Windows-en sare-diagnostikoak<ph name="END_LINK" />.</translation>
-<translation id="1772163372082567643">Aukeratu duzun zerbitzariak (<ph name="ORIGIN" />) goiburu bat ezarri du; haren arabera, jatorri-gidalerro bat aplikatuko zaie zerbitzari hartako eskaera guztiei. Alabaina, goiburua oker dago eratuta; ondorioz, arakatzaileak ezin du gauzatu <ph name="SITE" /> webgunean sartzeko egin duzu eskaera. Webgunearen segurtasuna eta beste propietate batzuk konfiguratzeko erabili ohi dituzte webguneen eragileek jatorri-gidalerroak.</translation>
+<translation id="1772163372082567643">Aukeratu duzun zerbitzariak (<ph name="ORIGIN" />) goiburu bat ezarri du; haren arabera, jatorri-gidalerro bat aplikatuko zaie zerbitzari hartako eskaera guztiei. Alabaina, goiburua oker dago eratuta; ondorioz, arakatzaileak ezin du gauzatu <ph name="SITE" /> webgunean sartzeko egin duzun eskaera. Webgunearen segurtasuna eta beste propietate batzuk konfiguratzeko erabili ohi dituzte webguneen eragileek jatorri-gidalerroak.</translation>
 <translation id="1778646502362731194">JIS B0</translation>
 <translation id="1783075131180517613">Eguneratu sinkronizatzeko pasaesaldia.</translation>
 <translation id="1787142507584202372">Ireki dituzun fitxak agertuko dira hemen</translation>
@@ -220,7 +220,6 @@
 <translation id="1838374766361614909">Garbitu bilaketa</translation>
 <translation id="1839551713262164453">Gidalerroen balioen balidazioak huts egin du eta erroreak ditu</translation>
 <translation id="1842969606798536927">Ordaindu</translation>
-<translation id="1852694792039666893">Erabili Google-ko kontua pasahitz seguru bat iradokitzeko</translation>
 <translation id="1871208020102129563">Proxy-zerbitzari finkoak erabiltzeko konfiguratu da proxya, ez .pac scripteko URLak erabiltzeko.</translation>
 <translation id="1871284979644508959">Derrigorrezko eremua</translation>
 <translation id="1875512691959384712">Google Inprimakiak</translation>
@@ -405,7 +404,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Doikuntzarik onena</translation>
 <translation id="2691924980723297736">Segurtasun-abisua</translation>
-<translation id="2696268945573510710">Erabili Google-ko kontuan gordetako pasahitzak</translation>
 <translation id="2699302886720511147">Onartzen diren txartelak</translation>
 <translation id="2701514975700770343">Ahuspez</translation>
 <translation id="2702801445560668637">Zerrenda</translation>
@@ -452,7 +450,6 @@
 <translation id="2915068235268646559">Hutsegitearen ordua: <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Itxi beste programa batzuk</translation>
 <translation id="2922350208395188000">Ezin da egiaztatu zerbitzariaren ziurtagiria.</translation>
-<translation id="2924027812781652774">Hasi saioa Google-ko kontuan gordetako pasahitzak erabiltzeko</translation>
 <translation id="2925673989565098301">Entregatzeko modua</translation>
 <translation id="2928905813689894207">Fakturazio-helbidea</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> eta beste <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> eta beste <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
@@ -701,7 +698,7 @@
     Abisu honek dioena oker dagoela uste baduzu, joan https://bugs.chromium.org/p/chromium/issues/entry?template=Safety+Tips+Appeals helbidera.</translation>
 <translation id="3987940399970879459">1 MB baino gutxiago</translation>
 <translation id="3990250421422698716">Tolestura-marjina</translation>
-<translation id="3996311196211510766"><ph name="ORIGIN" /> webguneak bere eskaera guztiei jatorri-gidalerro bat aplikatzeko eskatu du, baina ezin da aplikatu gidalerroa une honetan.</translation>
+<translation id="3996311196211510766"><ph name="ORIGIN" /> webguneak hartarako eskaera guztiei jatorri-gidalerro bat aplikatzeko eskatu du, baina ezin da aplikatu gidalerroa une honetan.</translation>
 <translation id="40103911065039147">{URL_count,plural, =1{1 web-orri dago inguruan}other{# web-orri daude inguruan}}</translation>
 <translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} orri daukan PDF dokumentua}other{{COUNT} orri dauzkan PDF dokumentua}}</translation>
 <translation id="4030383055268325496">&amp;Desegin gehitzea</translation>
diff --git a/components/strings/components_strings_fa.xtb b/components/strings/components_strings_fa.xtb
index 0e6a99dd..d882589 100644
--- a/components/strings/components_strings_fa.xtb
+++ b/components/strings/components_strings_fa.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">پاک کردن جستجو</translation>
 <translation id="1839551713262164453">اعتبارسنجی مقادیر خط‌مشی با خطا متوقف شد</translation>
 <translation id="1842969606798536927">پرداخت</translation>
-<translation id="1852694792039666893">‏استفاده از «حساب Google» برای پیشنهاد دادن گذرواژه قوی</translation>
 <translation id="1871208020102129563">‏تنظیم پروکسی به گونه‌ای است که از سرورهای ثابت پروکسی استفاده کند و از آدرس اسکریپت pac. استفاده نکند.</translation>
 <translation id="1871284979644508959">قسمت الزامی</translation>
 <translation id="1875512691959384712">‏فرم‌نگار Google</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">بهترین اندازه</translation>
 <translation id="2691924980723297736">هشدار ایمنی</translation>
-<translation id="2696268945573510710">‏استفاده از گذرواژه‌های ذخیره‌شده در «حساب Google»</translation>
 <translation id="2699302886720511147">کارت‌های قابل‌‌قبول</translation>
 <translation id="2701514975700770343">روبه‌پایین</translation>
 <translation id="2702801445560668637">فهرست خواندن</translation>
@@ -456,7 +454,6 @@
 <translation id="2915068235268646559">خرابی از <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">برنامه‌های دیگر را ببندید</translation>
 <translation id="2922350208395188000">گواهی سرور بررسی نمی‌شود.</translation>
-<translation id="2924027812781652774">‏ورود به سیستم برای استفاده از گذرواژه‌های ذخیره‌شده در «حساب Google»</translation>
 <translation id="2925673989565098301">روش ارسال</translation>
 <translation id="2928905813689894207">نشانی صورت‌حساب</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> و <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> نشانی دیگر}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> و <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> نشانی دیگر}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> و <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> نشانی دیگر}}</translation>
diff --git a/components/strings/components_strings_fi.xtb b/components/strings/components_strings_fi.xtb
index 5f8913ff8..4d4c83c7 100644
--- a/components/strings/components_strings_fi.xtb
+++ b/components/strings/components_strings_fi.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Tyhjennä haku</translation>
 <translation id="1839551713262164453">Käytäntöarvojen vahvistus epäonnistui sisältäen virheitä</translation>
 <translation id="1842969606798536927">Maksa</translation>
-<translation id="1852694792039666893">Ehdota vahvaa salasanaa käyttämällä Google-tiliä</translation>
 <translation id="1871208020102129563">Välityspalvelin on asetettu käyttämään kiinteitä välityspalvelimia, ei .pac-URL-osoitetta.</translation>
 <translation id="1871284979644508959">Pakollinen tieto</translation>
 <translation id="1875512691959384712">Google Forms</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Sopivin koko</translation>
 <translation id="2691924980723297736">Turvallisuusvaroitus</translation>
-<translation id="2696268945573510710">Käytä Google-tilillesi tallennettuja salasanoja</translation>
 <translation id="2699302886720511147">Hyväksytyt kortit</translation>
 <translation id="2701514975700770343">Tulostuspuoli alaspäin</translation>
 <translation id="2702801445560668637">Lukulista</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Kaatuminen <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Sulje muita ohjelmia.</translation>
 <translation id="2922350208395188000">Palvelimen varmennetta ei voi tarkistaa.</translation>
-<translation id="2924027812781652774">Kirjaudu sisään käyttääksesi Google-tilillesi tallennettuja salasanoja</translation>
 <translation id="2925673989565098301">Toimitustapa</translation>
 <translation id="2928905813689894207">Laskutusosoite</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" /><ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{ ja <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> toinen}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ja <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> muuta}}</translation>
diff --git a/components/strings/components_strings_fil.xtb b/components/strings/components_strings_fil.xtb
index c35fd253..85fc1ce3 100644
--- a/components/strings/components_strings_fil.xtb
+++ b/components/strings/components_strings_fil.xtb
@@ -178,6 +178,7 @@
 <translation id="1671391448414634642">Simula ngayon ay ita-translate na sa <ph name="TARGET_LANGUAGE" /> ang mga page na nasa <ph name="SOURCE_LANGUAGE" />.</translation>
 <translation id="1676269943528358898">Karaniwang gumagamit ang <ph name="SITE" /> ng pag-encrypt upang protektahan ang iyong impormasyon. Noong sinubukang kumonekta ng Chrome sa <ph name="SITE" /> sa pagkakataong ito, nagbalik ang website ng mga hindi pangkaraniwan at maling kredensyal. Maaari itong mangyari kapag sinusubukan ng isang attacker na magpanggap bilang <ph name="SITE" />, o naputol ang koneksyon dahil sa isang screen ng pag-sign in sa Wi-Fi. Secure pa rin ang iyong impormasyon dahil inihinto ng Google Chrome ang koneksyon bago magkaroon ng palitan ng anumang data.</translation>
 <translation id="1682696192498422849">Short edge muna</translation>
+<translation id="168693727862418163">Hindi na-validate ang value ng patakarang ito sa schema nito at babalewalain ito.</translation>
 <translation id="168841957122794586">Naglalaman ang server certificate ng isang mahinang cryptographic key.</translation>
 <translation id="1697532407822776718">Handa ka na!</translation>
 <translation id="1703835215927279855">Letter</translation>
@@ -224,7 +225,6 @@
 <translation id="1838374766361614909">I-clear ang paghahanap</translation>
 <translation id="1839551713262164453">Hindi na-validate ang mga value ng patakaran at may mga error</translation>
 <translation id="1842969606798536927">Magbayad</translation>
-<translation id="1852694792039666893">Gamitin ang iyong Google account para magmungkahi ng mahirap hulaang password</translation>
 <translation id="1871208020102129563">Nakatakda ang proxy upang gumamit ng mga hindi nababagong proxy server, hindi ng isang .pac script URL.</translation>
 <translation id="1871284979644508959">Kinakailangang field</translation>
 <translation id="1875512691959384712">Google Forms</translation>
@@ -409,7 +409,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Pinakakasya</translation>
 <translation id="2691924980723297736">Babala sa kaligtasan</translation>
-<translation id="2696268945573510710">Gamitin ang mga password na naka-store sa iyong Google Account</translation>
 <translation id="2699302886720511147">Mga Tinatanggap na Card</translation>
 <translation id="2701514975700770343">Nakataob</translation>
 <translation id="2702801445560668637">Listahan ng Babasahin</translation>
@@ -458,7 +457,6 @@
 <translation id="2915068235268646559">Pag-crash mula noong <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Isara ang iba pang program</translation>
 <translation id="2922350208395188000">Hindi masuri ang certificate ng server.</translation>
-<translation id="2924027812781652774">Mag-sign in para magamit ang mga naka-store na password sa iyong Google Account</translation>
 <translation id="2925673989565098301">Paraan ng Paghahatid</translation>
 <translation id="2928905813689894207">Billing Address</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> at <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> pa}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> at <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> pa}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> at <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> pa}}</translation>
diff --git a/components/strings/components_strings_fr-CA.xtb b/components/strings/components_strings_fr-CA.xtb
index ac38152..68d4421 100644
--- a/components/strings/components_strings_fr-CA.xtb
+++ b/components/strings/components_strings_fr-CA.xtb
@@ -178,6 +178,7 @@
 <translation id="1671391448414634642">Les pages en <ph name="SOURCE_LANGUAGE" /> seront désormais traduites en <ph name="TARGET_LANGUAGE" />.</translation>
 <translation id="1676269943528358898">Un chiffrement est normalement utilisé sur le site <ph name="SITE" /> pour protéger vos données personnelles. Lors de la dernière tentative de connexion de Google Chrome au site <ph name="SITE" />, des identifiants inhabituels et incorrects ont été retournés. Cela peut arriver lorsqu'un individu malveillant tente de se faire passer pour <ph name="SITE" /> ou qu'un écran de connexion Wi-Fi a interrompu la connexion. Vos données restent sécurisées, car nous avons interrompu la connexion avant l'échange des données.</translation>
 <translation id="1682696192498422849">Bord court en premier</translation>
+<translation id="168693727862418163">La validation de la valeur de cette politique par rapport à son schéma a échoué. La politique sera ignorée.</translation>
 <translation id="168841957122794586">Le certificat du serveur contient une clé de chiffrement faible.</translation>
 <translation id="1697532407822776718">Vous êtes prêt!</translation>
 <translation id="1703835215927279855">Lettre</translation>
@@ -220,7 +221,6 @@
 <translation id="1838374766361614909">Effacer les termes de recherche</translation>
 <translation id="1839551713262164453">La validation des valeurs de politique a échoué avec des erreurs</translation>
 <translation id="1842969606798536927">Paiement</translation>
-<translation id="1852694792039666893">Utiliser votre compte Google pour suggérer un mot de passe fort</translation>
 <translation id="1871208020102129563">Le mandataire est configuré pour utiliser des serveurs mandataires fixes et non une adresse URL de script .pac.</translation>
 <translation id="1871284979644508959">Champ obligatoire</translation>
 <translation id="1875512691959384712">Google Formulaires</translation>
@@ -405,7 +405,6 @@
 <translation id="2684561033061424857">11 po x 12 po</translation>
 <translation id="2687555958734450033">Ajustement optimal</translation>
 <translation id="2691924980723297736">Avertissement de sécurité</translation>
-<translation id="2696268945573510710">Utiliser les mots de passe stockés dans votre compte Google</translation>
 <translation id="2699302886720511147">Cartes acceptées</translation>
 <translation id="2701514975700770343">Face vers le bas</translation>
 <translation id="2702801445560668637">Liste de lecture</translation>
@@ -452,7 +451,6 @@
 <translation id="2915068235268646559">Plantage à <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Fermer les autres programmes</translation>
 <translation id="2922350208395188000">Impossible de vérifier le certificat du serveur.</translation>
-<translation id="2924027812781652774">Connectez-vous pour utiliser les mots de passe stockés dans votre compte Google</translation>
 <translation id="2925673989565098301">Mode de livraison rapide</translation>
 <translation id="2928905813689894207">Adresse de facturation</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> autre adresse}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> autre adresse}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> autres adresses}}</translation>
diff --git a/components/strings/components_strings_fr.xtb b/components/strings/components_strings_fr.xtb
index 52a6723..5553bf4 100644
--- a/components/strings/components_strings_fr.xtb
+++ b/components/strings/components_strings_fr.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Effacer la recherche</translation>
 <translation id="1839551713262164453">Échec de la validation des valeurs de règle avec des erreurs</translation>
 <translation id="1842969606798536927">Paiement</translation>
-<translation id="1852694792039666893">Utiliser votre compte Google pour obtenir une suggestion de mot de passe sécurisé</translation>
 <translation id="1871208020102129563">Le proxy est configuré pour utiliser des serveurs proxy déterminés, pas une URL de script .pac.</translation>
 <translation id="1871284979644508959">Veuillez compléter ce champ.</translation>
 <translation id="1875512691959384712">Google Forms</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Taille optimale</translation>
 <translation id="2691924980723297736">Avertissement de sécurité</translation>
-<translation id="2696268945573510710">Utiliser un mot de passe enregistré dans votre compte Google</translation>
 <translation id="2699302886720511147">Cartes acceptées</translation>
 <translation id="2701514975700770343">Vers le bas</translation>
 <translation id="2702801445560668637">Liste de lecture</translation>
@@ -456,7 +454,6 @@
 <translation id="2915068235268646559">Date et heure du plantage : <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Fermez les autres programmes</translation>
 <translation id="2922350208395188000">Impossible de vérifier le certificat du serveur.</translation>
-<translation id="2924027812781652774">Connectez-vous pour utiliser les mots de passe enregistrés dans votre compte Google</translation>
 <translation id="2925673989565098301">Mode de livraison</translation>
 <translation id="2928905813689894207">Adresse de facturation</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> autre}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> autre}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> autres}}</translation>
diff --git a/components/strings/components_strings_gl.xtb b/components/strings/components_strings_gl.xtb
index 88b22b3a..9367159 100644
--- a/components/strings/components_strings_gl.xtb
+++ b/components/strings/components_strings_gl.xtb
@@ -223,7 +223,6 @@
 <translation id="1838374766361614909">Borrar busca</translation>
 <translation id="1839551713262164453">Producíronse erros na validación dos valores da política</translation>
 <translation id="1842969606798536927">Pagar</translation>
-<translation id="1852694792039666893">Utilizar a túa Conta de Google para suxerir un contrasinal seguro</translation>
 <translation id="1871208020102129563">O proxy está configurado para utilizar servidores proxy fixos, non un URL de script .pac.</translation>
 <translation id="1871284979644508959">O campo é obrigatorio</translation>
 <translation id="1875512691959384712">Formularios de Google</translation>
@@ -408,7 +407,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Tamaño predeterminado</translation>
 <translation id="2691924980723297736">Advertencia de seguranza</translation>
-<translation id="2696268945573510710">Utilizar contrasinais almacenados na túa Conta de Google</translation>
 <translation id="2699302886720511147">Acéptanse tarxetas</translation>
 <translation id="2701514975700770343">Cara abaixo</translation>
 <translation id="2702801445560668637">Lista de lectura</translation>
@@ -455,7 +453,6 @@
 <translation id="2915068235268646559">Fallo (<ph name="CRASH_TIME" />)</translation>
 <translation id="2916038427272391327">Pecha outros programas</translation>
 <translation id="2922350208395188000">Non se pode comprobar o certificado do servidor.</translation>
-<translation id="2924027812781652774">Iniciar sesión para utilizar contrasinais almacenados na túa Conta de Google</translation>
 <translation id="2925673989565098301">Método de entrega</translation>
 <translation id="2928905813689894207">Enderezo de facturación</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> máis}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> máis}}</translation>
diff --git a/components/strings/components_strings_gu.xtb b/components/strings/components_strings_gu.xtb
index 851372c..1e277c4a 100644
--- a/components/strings/components_strings_gu.xtb
+++ b/components/strings/components_strings_gu.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">શોધ સાફ કરો</translation>
 <translation id="1839551713262164453">ભૂલના લીધે નીતિ મૂલ્યોની માન્યતા નિષ્ફળ થઈ</translation>
 <translation id="1842969606798536927">ચુકવણી કરો</translation>
-<translation id="1852694792039666893">એક મજબૂત પાસવર્ડ સૂચવવા માટે તમારા Google એકાઉન્ટનો ઉપયોગ કરો</translation>
 <translation id="1871208020102129563">પ્રૉક્સી નક્કી કરેલા પ્રૉક્સી સર્વરનો ઉપયોગ કરવા માટે સેટ કરેલી છે, .pac સ્ક્રિપ્ટ URL નથી.</translation>
 <translation id="1871284979644508959">જરૂરી ફીલ્ડ</translation>
 <translation id="1875512691959384712">Google ફોર્મ્સ</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">શ્રેષ્ઠ ફિટ</translation>
 <translation id="2691924980723297736">સલામતીની ચેતવણી</translation>
-<translation id="2696268945573510710">તમારા Google એકાઉન્ટમાં સ્ટોર કરવામાં આવેલા પાસવર્ડનો ઉપયોગ કરો</translation>
 <translation id="2699302886720511147">સ્વીકૃત કાર્ડ</translation>
 <translation id="2701514975700770343">નીચે તરફ</translation>
 <translation id="2702801445560668637">વાંચન સૂચિ</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" /> પછીનો ક્રૅશ</translation>
 <translation id="2916038427272391327">અન્ય પ્રોગ્રામ બંધ કરો</translation>
 <translation id="2922350208395188000">સર્વરનું પ્રમાણપત્ર તપાસી શકાતું નથી.</translation>
-<translation id="2924027812781652774">તમારા Google એકાઉન્ટમાં સ્ટોર કરેલા પાસવર્ડનો ઉપયોગ કરવા માટે સાઇન ઇન કરો</translation>
 <translation id="2925673989565098301">વિતરણ પદ્ધતિ</translation>
 <translation id="2928905813689894207">બિલિંગનું સરનામું</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> અને <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> વધુ}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> અને <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> વધુ}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> અને <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> વધુ}}</translation>
diff --git a/components/strings/components_strings_hi.xtb b/components/strings/components_strings_hi.xtb
index bfc676f..ef1ec18 100644
--- a/components/strings/components_strings_hi.xtb
+++ b/components/strings/components_strings_hi.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">खोज साफ़ करें</translation>
 <translation id="1839551713262164453">गड़बड़ियों के चलते नीति मानों की पुष्टि नहीं हो सकी</translation>
 <translation id="1842969606798536927">पैसे चुकाएं</translation>
-<translation id="1852694792039666893">मज़बूत पासवर्ड सुझाने के लिए अपने Google खाते का इस्तेमाल करें</translation>
 <translation id="1871208020102129563">प्रॉक्‍सी की सेटिंग इस तरह से की गई है कि वह फ़िक्‍स्‍ड प्रॉक्‍सी सर्वर इस्तेमाल करे, न कि .pac स्‍क्रिप्‍ट यूआरअल.</translation>
 <translation id="1871284979644508959">ज़रूरी फ़ील्ड</translation>
 <translation id="1875512691959384712">Google फ़ॉर्म</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">सबसे बढ़िया फ़िटिंग</translation>
 <translation id="2691924980723297736">सुरक्षा की चेतावनी</translation>
-<translation id="2696268945573510710">अपने Google खाते में सेव किए गए पासवर्ड इस्तेमाल करें</translation>
 <translation id="2699302886720511147">स्वीकार किए जाने वाले कार्ड</translation>
 <translation id="2701514975700770343">उलटा करके रखें</translation>
 <translation id="2702801445560668637">पठन सूची</translation>
@@ -456,7 +454,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" /> की खराबी रिपोर्ट</translation>
 <translation id="2916038427272391327">दूसरे प्रोग्राम बंद करें</translation>
 <translation id="2922350208395188000">सर्वर प्रमाणपत्र की जाँच नहीं की जा सकती.</translation>
-<translation id="2924027812781652774">अपने Google खाते में सेव किए गए पासवर्ड इस्तेमाल करने के लिए साइन इन करें</translation>
 <translation id="2925673989565098301">डिलीवरी का तरीका</translation>
 <translation id="2928905813689894207">बिलिंग पता</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> और <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> अन्य}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> और <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> अन्य}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> और <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> अन्य}}</translation>
diff --git a/components/strings/components_strings_hr.xtb b/components/strings/components_strings_hr.xtb
index e018f26..33389bf 100644
--- a/components/strings/components_strings_hr.xtb
+++ b/components/strings/components_strings_hr.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Brisanje pretraživanja</translation>
 <translation id="1839551713262164453">Potvrđivanje vrijednosti pravila nije uspjelo zbog pogrešaka</translation>
 <translation id="1842969606798536927">Plaćanje</translation>
-<translation id="1852694792039666893">Upotrijebite Google račun za predlaganje snažne zaporke</translation>
 <translation id="1871208020102129563">Proxy poslužitelj postavljen je na upotrebu fiksnih proxy poslužitelja, a ne URL .pac skripte.</translation>
 <translation id="1871284979644508959">Obavezno polje</translation>
 <translation id="1875512691959384712">Google obrasci</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Najbolja veličina</translation>
 <translation id="2691924980723297736">Sigurnosno upozorenje</translation>
-<translation id="2696268945573510710">Koristite zaporke pohranjene na vašem Google računu</translation>
 <translation id="2699302886720511147">Prihvaćene kartice</translation>
 <translation id="2701514975700770343">Prema dolje</translation>
 <translation id="2702801445560668637">Popis za čitanje</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Rušenje: <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Zatvorite ostale programe</translation>
 <translation id="2922350208395188000">Certifikat poslužitelja nije moguće provjeriti.</translation>
-<translation id="2924027812781652774">Prijavite se kako biste upotrebljavali zaporke pohranjene na vašem Google računu</translation>
 <translation id="2925673989565098301">Način dostave</translation>
 <translation id="2928905813689894207">Adresa za naplatu</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_hu.xtb b/components/strings/components_strings_hu.xtb
index 0143bbb..5a0ac2eb 100644
--- a/components/strings/components_strings_hu.xtb
+++ b/components/strings/components_strings_hu.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Keresett kifejezés törlése</translation>
 <translation id="1839551713262164453">A házirendértékek ellenőrzése hibák miatt sikertelen</translation>
 <translation id="1842969606798536927">Fizetés</translation>
-<translation id="1852694792039666893">A Google-fiók használata erős jelszó generálásához</translation>
 <translation id="1871208020102129563">A proxy fix proxyszerverek használatára van beállítva, nem pedig .pac típusú szkript URL címének használatára.</translation>
 <translation id="1871284979644508959">Kötelező mező</translation>
 <translation id="1875512691959384712">Google Űrlapok</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Legjobb illeszkedés</translation>
 <translation id="2691924980723297736">Biztonsági figyelmeztetés</translation>
-<translation id="2696268945573510710">A Google-fiókban tárolt jelszavak használata</translation>
 <translation id="2699302886720511147">Elfogadott kártyák</translation>
 <translation id="2701514975700770343">Lefelé fordítva</translation>
 <translation id="2702801445560668637">Olvasási lista</translation>
@@ -456,7 +454,6 @@
 <translation id="2915068235268646559">Összeomlás – <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Zárja be a többi programot</translation>
 <translation id="2922350208395188000">A szerver tanúsítványát nem sikerült leellenőrizni.</translation>
-<translation id="2924027812781652774">Jelentkezzen be a Google-fiókjában tárolt jelszavak használatához</translation>
 <translation id="2925673989565098301">Kézbesítési mód</translation>
 <translation id="2928905813689894207">Számlázási cím</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> és további <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> és további <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_hy.xtb b/components/strings/components_strings_hy.xtb
index 8e2f6a78..e3a4019 100644
--- a/components/strings/components_strings_hy.xtb
+++ b/components/strings/components_strings_hy.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Մաքրել որոնումը</translation>
 <translation id="1839551713262164453">Չհաջողվեց ստուգել կանոնի արժեքները</translation>
 <translation id="1842969606798536927">Վճարել</translation>
-<translation id="1852694792039666893">Հուսալի գաղտնաբառ ստեղծելու համար օգտագործեք ձեր Google հաշիվը</translation>
 <translation id="1871208020102129563">Ընտրված է ֆիքսված պրոքսի-սերվերների, այլ ոչ PAC սկրիպտի URL-ի օգտագործումը:</translation>
 <translation id="1871284979644508959">Պարտադիր դաշտ</translation>
 <translation id="1875512691959384712">Google Ձևաթղթեր</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Լավագույն տարբերակ</translation>
 <translation id="2691924980723297736">Զգուշացում</translation>
-<translation id="2696268945573510710">Օգտագործել Google հաշվում պահված գաղտնաբառերը</translation>
 <translation id="2699302886720511147">Քարտեր, որոնցով կարելի է վճարել</translation>
 <translation id="2701514975700770343">Երեսի կողմով ներքև</translation>
 <translation id="2702801445560668637">Ընթերցանության ցանկ</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Խափանման օրը և ժամը՝ <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Փակեք մյուս ծրագրերը</translation>
 <translation id="2922350208395188000">Հնարավոր չէ ստուգել սերվերի վկայագիրը:</translation>
-<translation id="2924027812781652774">Մուտք գործեք՝ Google հաշվում պահված գաղտնաբառերն օգտագործելու համար</translation>
 <translation id="2925673989565098301">Առաքման եղանակը</translation>
 <translation id="2928905813689894207">Վճարային հասցե</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> և ուղարկման ևս <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> տարբերակ}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> և ուղարկման ևս <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> տարբերակ}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> և ուղարկման ևս <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> տարբերակ}}</translation>
diff --git a/components/strings/components_strings_id.xtb b/components/strings/components_strings_id.xtb
index 815efcd..312e5750 100644
--- a/components/strings/components_strings_id.xtb
+++ b/components/strings/components_strings_id.xtb
@@ -220,7 +220,6 @@
 <translation id="1838374766361614909">Hapus penelusuran</translation>
 <translation id="1839551713262164453">Validasi nilai kebijakan gagal karena terjadi error</translation>
 <translation id="1842969606798536927">Bayar</translation>
-<translation id="1852694792039666893">Gunakan Akun Google Anda untuk menyarankan sandi yang kuat</translation>
 <translation id="1871208020102129563">Proxy disetel untuk menggunakan server proxy tetap, bukan URL skrip .pac.</translation>
 <translation id="1871284979644508959">Bidang wajib diisi</translation>
 <translation id="1875512691959384712">Google Formulir</translation>
@@ -405,7 +404,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Paling pas</translation>
 <translation id="2691924980723297736">Peringatan keamanan</translation>
-<translation id="2696268945573510710">Gunakan sandi yang disimpan di Akun Google Anda</translation>
 <translation id="2699302886720511147">Kartu yang Diterima</translation>
 <translation id="2701514975700770343">Menghadap ke bawah</translation>
 <translation id="2702801445560668637">Daftar Bacaan</translation>
@@ -454,7 +452,6 @@
 <translation id="2915068235268646559">Error dari <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Tutup program lain</translation>
 <translation id="2922350208395188000">Sertifikat server tidak dapat diperiksa.</translation>
-<translation id="2924027812781652774">Login untuk menggunakan sandi yang disimpan di Akun Google Anda</translation>
 <translation id="2925673989565098301">Metode Pengiriman</translation>
 <translation id="2928905813689894207">Alamat Penagihan</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> dan <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> lainnya}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> dan <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> lainnya}}</translation>
diff --git a/components/strings/components_strings_is.xtb b/components/strings/components_strings_is.xtb
index 07656b6..fbd121c 100644
--- a/components/strings/components_strings_is.xtb
+++ b/components/strings/components_strings_is.xtb
@@ -225,7 +225,6 @@
 <translation id="1838374766361614909">Hreinsa leit</translation>
 <translation id="1839551713262164453">Prófun á reglugildum mistókst og skilaði villum</translation>
 <translation id="1842969606798536927">Greiða</translation>
-<translation id="1852694792039666893">Nota Google reikninginn þinn til að fá tillögu um traust aðgangsorð</translation>
 <translation id="1871208020102129563">Proxy er stillt á að nota fasta proxy-þjóna en ekki vefslóð á .pac-skriftu.</translation>
 <translation id="1871284979644508959">Nauðsynlegur reitur</translation>
 <translation id="1875512691959384712">Google eyðublöð</translation>
@@ -410,7 +409,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Kjörstærð</translation>
 <translation id="2691924980723297736">Öryggisviðvörun</translation>
-<translation id="2696268945573510710">Nota aðgangsorð sem eru vistuð á Google reikningnum</translation>
 <translation id="2699302886720511147">Greiðslukort sem tekið er við</translation>
 <translation id="2701514975700770343">Snýr niður</translation>
 <translation id="2702801445560668637">Leslisti</translation>
@@ -459,7 +457,6 @@
 <translation id="2915068235268646559">Hrun frá <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Lokaðu öðrum forritum</translation>
 <translation id="2922350208395188000">Ekki er hægt að kanna vottorð þjónsins.</translation>
-<translation id="2924027812781652774">Skráðu þig inn til að nota aðgangsorð sem eru vistuð á Google reikningnum</translation>
 <translation id="2925673989565098301">Afhendingarmáti</translation>
 <translation id="2928905813689894207">Heimilisfang greiðanda</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> í viðbót}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> í viðbót}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> í viðbót}}</translation>
diff --git a/components/strings/components_strings_it.xtb b/components/strings/components_strings_it.xtb
index 9daf5d2..91147f1 100644
--- a/components/strings/components_strings_it.xtb
+++ b/components/strings/components_strings_it.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Cancella ricerca</translation>
 <translation id="1839551713262164453">Convalida dei valori della norma non riuscita con errori</translation>
 <translation id="1842969606798536927">Paga</translation>
-<translation id="1852694792039666893">Usa il tuo Account Google per generare una password efficace</translation>
 <translation id="1871208020102129563">L'impostazione del proxy prevede l'utilizzo di server proxy fissi, non di un URL script .pac.</translation>
 <translation id="1871284979644508959">Campo obbligatorio</translation>
 <translation id="1875512691959384712">Moduli Google</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Dimensioni predefinite</translation>
 <translation id="2691924980723297736">Avviso di sicurezza</translation>
-<translation id="2696268945573510710">Usa le password memorizzate nel tuo Account Google</translation>
 <translation id="2699302886720511147">Carte accettate</translation>
 <translation id="2701514975700770343">A faccia in giù</translation>
 <translation id="2702801445560668637">Elenco di lettura</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Arresto anomalo dalle ore <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Chiudi altri programmi</translation>
 <translation id="2922350208395188000">Il certificato del server non può essere verificato.</translation>
-<translation id="2924027812781652774">Accedi per usare le password memorizzate nel tuo Account Google</translation>
 <translation id="2925673989565098301">Metodo di consegna</translation>
 <translation id="2928905813689894207">Indirizzo di fatturazione</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> altro}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e altri <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_iw.xtb b/components/strings/components_strings_iw.xtb
index 5ed9d3ed..e5e21d1 100644
--- a/components/strings/components_strings_iw.xtb
+++ b/components/strings/components_strings_iw.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">ניקוי חיפוש</translation>
 <translation id="1839551713262164453">אימות ערכי המדיניות נכשל והתרחשו שגיאות</translation>
 <translation id="1842969606798536927">לתשלום</translation>
-<translation id="1852694792039666893">‏שימוש בחשבון Google לקבלת הצעה לסיסמה חזקה</translation>
 <translation id="1871208020102129563">‏שרת ה-Proxy מוגדר להשתמש בשרתי Proxy קבועים, לא בכתובת אתר של סקריפט ‎.Pac</translation>
 <translation id="1871284979644508959">שדה חובה</translation>
 <translation id="1875512691959384712">Google Forms</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">ההתאמה הטובה ביותר</translation>
 <translation id="2691924980723297736">אזהרת אבטחה</translation>
-<translation id="2696268945573510710">‏שימוש בסיסמאות המאוחסנות בחשבון Google</translation>
 <translation id="2699302886720511147">כרטיסים שהסוחר מקבל</translation>
 <translation id="2701514975700770343">פנים כלפי מטה</translation>
 <translation id="2702801445560668637">רשימת קריאה</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">קריסה משעה <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">סגירת תוכניות אחרות</translation>
 <translation id="2922350208395188000">לא ניתן לבדוק את אישור השרת.</translation>
-<translation id="2924027812781652774">‏כדי להשתמש בסיסמאות המאוחסנות בחשבון Google, עליך להיכנס שוב לחשבון</translation>
 <translation id="2925673989565098301">שיטת משלוח</translation>
 <translation id="2928905813689894207">כתובת לחיוב</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ועוד <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}two{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ועוד <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ועוד <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ועוד <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_ja.xtb b/components/strings/components_strings_ja.xtb
index 4676f19..d23c8f2a 100644
--- a/components/strings/components_strings_ja.xtb
+++ b/components/strings/components_strings_ja.xtb
@@ -178,6 +178,7 @@
 <translation id="1671391448414634642">今後、<ph name="SOURCE_LANGUAGE" />のページは<ph name="TARGET_LANGUAGE" />に翻訳されます。</translation>
 <translation id="1676269943528358898"><ph name="SITE" /> では通常、暗号化して情報を保護しています。今回、Google Chrome から <ph name="SITE" /> への接続試行時に、このウェブサイトからいつもとは異なる誤った認証情報が返されました。悪意のあるユーザーが <ph name="SITE" /> になりすまそうとしているか、Wi-Fi ログイン画面で接続が中断された可能性があります。データのやり取りが行われる前に Google Chrome によって接続が停止されたため、情報は引き続き保護されています。</translation>
 <translation id="1682696192498422849">短辺から</translation>
+<translation id="168693727862418163">このポリシーの値は、スキーマの検証でエラーとなったため無視されます。</translation>
 <translation id="168841957122794586">サーバー証明書に脆弱な暗号鍵が含まれています。</translation>
 <translation id="1697532407822776718">設定が完了しました。</translation>
 <translation id="1703835215927279855">Letter</translation>
@@ -220,7 +221,6 @@
 <translation id="1838374766361614909">検索をクリア</translation>
 <translation id="1839551713262164453">ポリシーの値を検証できませんでした(エラーが発生しました)</translation>
 <translation id="1842969606798536927">お支払い</translation>
-<translation id="1852694792039666893">Google アカウントを使用して安全なパスワードを提示する</translation>
 <translation id="1871208020102129563">プロキシは .pac スクリプト URL ではなく固定プロキシ サーバーを使用するように設定されています。</translation>
 <translation id="1871284979644508959">必須フィールド</translation>
 <translation id="1875512691959384712">Google フォーム</translation>
@@ -405,7 +405,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">最適サイズ</translation>
 <translation id="2691924980723297736">安全性に関する警告</translation>
-<translation id="2696268945573510710">Google アカウントに保存したパスワードを使用する</translation>
 <translation id="2699302886720511147">利用可能なカード</translation>
 <translation id="2701514975700770343">下向き</translation>
 <translation id="2702801445560668637">リーディング リスト</translation>
@@ -452,7 +451,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" /> のクラッシュ</translation>
 <translation id="2916038427272391327">他のプログラムを終了する</translation>
 <translation id="2922350208395188000">サーバーの証明書を確認できません。</translation>
-<translation id="2924027812781652774">Google アカウントに保存したパスワードを使用するには、ログインしてください</translation>
 <translation id="2925673989565098301">配達方法</translation>
 <translation id="2928905813689894207">請求先住所</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" />(他 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> 件)}other{<ph name="SHIPPING_ADDRESS_PREVIEW" />(他 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> 件)}}</translation>
diff --git a/components/strings/components_strings_ka.xtb b/components/strings/components_strings_ka.xtb
index c219cbdf..b23437c 100644
--- a/components/strings/components_strings_ka.xtb
+++ b/components/strings/components_strings_ka.xtb
@@ -220,7 +220,6 @@
 <translation id="1838374766361614909">ძიების გასუფთავება</translation>
 <translation id="1839551713262164453">წესების მნიშვნელობების დადასტურება ვერ მოხერხდა შეცდომების გამო</translation>
 <translation id="1842969606798536927">გადახდა</translation>
-<translation id="1852694792039666893">ძლიერი პაროლის შემოსათავაზებლად გამოიყენეთ თქვენი Google ანგარიში</translation>
 <translation id="1871208020102129563">პროქსი შექმნილია ფიქსირებული პროქსის სერვერების გამოსაყენებლად, არა .pac script URL-ის.</translation>
 <translation id="1871284979644508959">აუცილებელი ველი</translation>
 <translation id="1875512691959384712">Google Forms</translation>
@@ -405,7 +404,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">საუკეთესოდ მორგება</translation>
 <translation id="2691924980723297736">გაფრთხილება უსაფრთხოების შესახებ</translation>
-<translation id="2696268945573510710">Google ანგარიშში შენახული პაროლების გამოყენება</translation>
 <translation id="2699302886720511147">მისაღები ბარათები</translation>
 <translation id="2701514975700770343">ნაბეჭდი მხარით დაღმა</translation>
 <translation id="2702801445560668637">საკითხავი სია</translation>
@@ -452,7 +450,6 @@
 <translation id="2915068235268646559">ავარიულად გათიშვა (<ph name="CRASH_TIME" />)</translation>
 <translation id="2916038427272391327">სხვა პროგრამების დახურვა</translation>
 <translation id="2922350208395188000">სერვერის სერთიფიკატი ვერ მოწმდება.</translation>
-<translation id="2924027812781652774">თქვენს Google ანგარიშში შენახული პაროლების გამოსაყენებლად შედით სისტემაში</translation>
 <translation id="2925673989565098301">მიწოდების მეთოდი</translation>
 <translation id="2928905813689894207">ბილინგის მისამართი</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> და <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> სხვა}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> და <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> სხვა}}</translation>
diff --git a/components/strings/components_strings_kk.xtb b/components/strings/components_strings_kk.xtb
index fa2f5120..eb8fce22 100644
--- a/components/strings/components_strings_kk.xtb
+++ b/components/strings/components_strings_kk.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Іздеуді тазарту</translation>
 <translation id="1839551713262164453">Қателерге байланысты саясат мәндері тексерілмеді</translation>
 <translation id="1842969606798536927">Төлем</translation>
-<translation id="1852694792039666893">Күрделі құпия сөз жасау үшін Google есептік жазбаңызды пайдалану</translation>
 <translation id="1871208020102129563">Прокси .pac сценарий URL мекенжайын емес, бекітілген прокси серверлерін пайдалануға орнатылған.</translation>
 <translation id="1871284979644508959">Міндетті өріс</translation>
 <translation id="1875512691959384712">Google Forms</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Ең оңтайлы</translation>
 <translation id="2691924980723297736">Қауіпсіздік туралы ескерту</translation>
-<translation id="2696268945573510710">Google есептік жазбаңызда сақталған құпия сөздерді пайдалану</translation>
 <translation id="2699302886720511147">Қабылданатын карталар</translation>
 <translation id="2701514975700770343">Төмен қарату</translation>
 <translation id="2702801445560668637">Оқу тізімі</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Бұзылу уақыты: <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Басқа бағдарламаларды жабу</translation>
 <translation id="2922350208395188000">Сервердің сертификатын тексеру мүмкін емес.</translation>
-<translation id="2924027812781652774">Google есептік жазбаңызда сақталған құпия сөздерді пайдалану үшін кіру</translation>
 <translation id="2925673989565098301">Жеткізу әдісі</translation>
 <translation id="2928905813689894207">Төлем мекенжайы</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> және тағы <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> және тағы <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_km.xtb b/components/strings/components_strings_km.xtb
index 94afee7..f08aecb 100644
--- a/components/strings/components_strings_km.xtb
+++ b/components/strings/components_strings_km.xtb
@@ -226,7 +226,6 @@
 <translation id="1838374766361614909">ជម្រះការស្វែងរក</translation>
 <translation id="1839551713262164453">មិន​អាច​បញ្ជាក់​តម្លៃត្រឹមត្រូវ​សម្រាប់​គោលការណ៍​បានទេ​ដោយសារ​មានបញ្ហា</translation>
 <translation id="1842969606798536927">ចំណាយ</translation>
-<translation id="1852694792039666893">ប្រើគណនី Google របស់អ្នក ដើម្បីណែនាំពាក្យសម្ងាត់ខ្លាំង</translation>
 <translation id="1871208020102129563">ប្រូកស៊ីត្រូវបានកំណត់ដើម្បីប្រើម៉ាស៊ីនមេប្រូកស៊ីថេរ មិនមែន URL ស្គ្រីបផេកទេ។</translation>
 <translation id="1871284979644508959">ប្រអប់ដែលតម្រូវឲ្យបំពេញ</translation>
 <translation id="1875512691959384712">Google ទម្រង់បែបបទ</translation>
@@ -412,7 +411,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">ស័ក្តិសម​បំផុត</translation>
 <translation id="2691924980723297736">ការព្រមាន​អំពីសុវត្ថិភាព</translation>
-<translation id="2696268945573510710">ប្រើពាក្យសម្ងាត់ដែលរក្សាទុកនៅក្នុងគណនី Google របស់អ្នក</translation>
 <translation id="2699302886720511147">បណ្ណដែលទទួលយក</translation>
 <translation id="2701514975700770343">ផ្កាប់ចុះ</translation>
 <translation id="2702801445560668637">បញ្ជីអាន</translation>
@@ -461,7 +459,6 @@
 <translation id="2915068235268646559">ការគាំងពី <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">បិទកម្មវិធីផ្សេងទៀត</translation>
 <translation id="2922350208395188000">វិញ្ញាបនប័ត្រម៉ាស៊ីនមេមិនអាចត្រូវបានពិនិត្យទេ។</translation>
-<translation id="2924027812781652774">ចូលគណនី ដើម្បីប្រើ​ពាក្យសម្ងាត់​ដែលរក្សាទុក​នៅក្នុងគណនី Google របស់អ្នក</translation>
 <translation id="2925673989565098301">មធ្យោបាយ​ចែកចាយ​</translation>
 <translation id="2928905813689894207">អាសយដ្ឋានទូទាត់​វិក្កយបត្រ</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> និង <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ទៀត}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> និង <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ទៀត}}</translation>
diff --git a/components/strings/components_strings_kn.xtb b/components/strings/components_strings_kn.xtb
index 686ca9a..6a967cc 100644
--- a/components/strings/components_strings_kn.xtb
+++ b/components/strings/components_strings_kn.xtb
@@ -223,7 +223,6 @@
 <translation id="1838374766361614909">ಹುಡುಕಾಟ ತೆರವುಗೊಳಿಸಿ</translation>
 <translation id="1839551713262164453">ದೋಷಗಳಿರುವ ಕಾರಣ ಕಾರ್ಯನೀತಿಯ ಮೌಲ್ಯಗಳ ಮೌಲ್ಯೀಕರಣವು ವಿಫಲವಾಗಿದೆ</translation>
 <translation id="1842969606798536927">ಪಾವತಿಸಿ</translation>
-<translation id="1852694792039666893">ಸದೃಢ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ಸೂಚಿಸಲು ನಿಮ್ಮ Google ಖಾತೆಯನ್ನು ಬಳಸಿ</translation>
 <translation id="1871208020102129563">.pac ಸ್ಕ್ರಿಪ್ಟ್ URL ಅಲ್ಲದೆ, ನಿಗಧಿತ ಪ್ರಾಕ್ಸಿ ಸರ್ವರ್‌ಗಳನ್ನು ಬಳಸಲು ಪ್ರಾಕ್ಸಿಯನ್ನು ಹೊಂದಿಸಲಾಗಿದೆ.</translation>
 <translation id="1871284979644508959">ಅಗತ್ಯವಿರುವ ಕ್ಷೇತ್ರ</translation>
 <translation id="1875512691959384712">Google ಫಾರ್ಮ್‌ಗಳು</translation>
@@ -408,7 +407,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">ಅತ್ಯುತ್ತಮ ಹೊಂದಿಕೆ</translation>
 <translation id="2691924980723297736">ಸುರಕ್ಷತೆಯ ಎಚ್ಚರಿಕೆ</translation>
-<translation id="2696268945573510710">ನಿಮ್ಮ Google ಖಾತೆಯಲ್ಲಿ ಸಂಗ್ರಹಣೆ ಮಾಡಲಾದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ಬಳಸಿ</translation>
 <translation id="2699302886720511147">ಸ್ವೀಕೃತ ಕಾರ್ಡ್‌ಗಳು</translation>
 <translation id="2701514975700770343">ಮುಖ ಕೆಳಗೆ</translation>
 <translation id="2702801445560668637">ಓದುವ ಪಟ್ಟಿ</translation>
@@ -455,7 +453,6 @@
 <translation id="2915068235268646559">ಕ್ರ್ಯಾಶ್ ಆದ ಸಮಯ <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">ಇತರ ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ಮುಚ್ಚಿ</translation>
 <translation id="2922350208395188000">ಸರ್ವರ್‌ನ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಪರಿಶೀಲಿಸಲಾಗುವುದಿಲ್ಲ.</translation>
-<translation id="2924027812781652774">ನಿಮ್ಮ Google ಖಾತೆಯಲ್ಲಿ ಸಂಗ್ರಹಣೆ ಮಾಡಲಾದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ಬಳಸಲು ಸೈನ್ ಇನ್ ಮಾಡಿ</translation>
 <translation id="2925673989565098301">ವಿತರಣೆ ವಿಧಾನ</translation>
 <translation id="2928905813689894207">ಬಿಲ್ಲಿಂಗ್ ವಿಳಾಸ</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ಮತ್ತು <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ಇನ್ನಷ್ಟು}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ಮತ್ತು <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ಇನ್ನಷ್ಟು}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ಮತ್ತು <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ಇನ್ನಷ್ಟು}}</translation>
diff --git a/components/strings/components_strings_ko.xtb b/components/strings/components_strings_ko.xtb
index 1b48f5f..218d5b4 100644
--- a/components/strings/components_strings_ko.xtb
+++ b/components/strings/components_strings_ko.xtb
@@ -220,7 +220,6 @@
 <translation id="1838374766361614909">검색어 지우기</translation>
 <translation id="1839551713262164453">오류가 발생하여 정책 값의 유효성을 검사하지 못했습니다.</translation>
 <translation id="1842969606798536927">결제</translation>
-<translation id="1852694792039666893">Google 계정을 사용하여 안전한 비밀번호 생성</translation>
 <translation id="1871208020102129563">프록시가 .pac 스크립트 URL이 아닌 고정 프록시 서버를 사용하도록 설정됩니다.</translation>
 <translation id="1871284979644508959">필수 입력란</translation>
 <translation id="1875512691959384712">Google 설문지</translation>
@@ -405,7 +404,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">자동 맞춤</translation>
 <translation id="2691924980723297736">안전 경고</translation>
-<translation id="2696268945573510710">Google 계정에 저장된 비밀번호 사용</translation>
 <translation id="2699302886720511147">사용할 수 있는 카드</translation>
 <translation id="2701514975700770343">인쇄면이 아래로</translation>
 <translation id="2702801445560668637">읽기 목록</translation>
@@ -452,7 +450,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" />에 비정상 종료 발생</translation>
 <translation id="2916038427272391327">다른 프로그램 닫기</translation>
 <translation id="2922350208395188000">서버 인증서를 확인할 수 없습니다.</translation>
-<translation id="2924027812781652774">로그인하여 Google 계정에 저장된 비밀번호 사용</translation>
 <translation id="2925673989565098301">배달 방법</translation>
 <translation id="2928905813689894207">청구서 수신 주소</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> 외 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />개}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> 외 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />개}}</translation>
diff --git a/components/strings/components_strings_ky.xtb b/components/strings/components_strings_ky.xtb
index 6ab70c8..77c1e19 100644
--- a/components/strings/components_strings_ky.xtb
+++ b/components/strings/components_strings_ky.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Изделип жаткан нерсени өчүрүү</translation>
 <translation id="1839551713262164453">Саясатта коюлган маанилерди ырастоодо ката кетип, ырастоо аткарылбай калды.</translation>
 <translation id="1842969606798536927">Төлөө</translation>
-<translation id="1852694792039666893">Google аккаунтуңуз менен татаал сырсөз түзүп алыңыз</translation>
 <translation id="1871208020102129563">Прокси .pac скрипт URL дарегин эмес, туруктуу прокси серверлерин колдонот деп коюлган.</translation>
 <translation id="1871284979644508959">Милдеттүү талаа</translation>
 <translation id="1875512691959384712">Google Формалар</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Туура формат</translation>
 <translation id="2691924980723297736">Коопсуздук эскертүүсү</translation>
-<translation id="2696268945573510710">Google аккаунтуңузда сакталган сырсөздөрдү колдонуңуз</translation>
 <translation id="2699302886720511147">Кабыл алынган карточкалар</translation>
 <translation id="2701514975700770343">Алдыңкы бетин ылдый каратып</translation>
 <translation id="2702801445560668637">Окуу тизмеси</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Бузулуу жөнүндө кабар саат <ph name="CRASH_TIME" /> алынды</translation>
 <translation id="2916038427272391327">Башка программаларды жабыңыз</translation>
 <translation id="2922350208395188000">Сервердин тастыктамасы текшерилбей жатат.</translation>
-<translation id="2924027812781652774">Google аккаунтуңузда сакталган сырсөздөрдү колдонуу үчүн аккаунтуңузга кириңиз</translation>
 <translation id="2925673989565098301">Жеткирүү ыкмасы</translation>
 <translation id="2928905813689894207">Төлөмдүн дареги</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> жана дагы <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> дарек}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> жана дагы <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> дарек}}</translation>
diff --git a/components/strings/components_strings_lo.xtb b/components/strings/components_strings_lo.xtb
index 0dc44ec..1a554ae5 100644
--- a/components/strings/components_strings_lo.xtb
+++ b/components/strings/components_strings_lo.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">ລຶບ​ການ​ຊອກ​ຫາ</translation>
 <translation id="1839551713262164453">ການກວດຮັບຮອງຄ່ານະໂຍບາຍບໍ່ສຳເລັດໂດຍມີຂໍ້ຜິດພາດ</translation>
 <translation id="1842969606798536927">ຈ່າຍ</translation>
-<translation id="1852694792039666893">ໃຊ້ບັນຊີ Google ຂອງທ່ານເພື່ອແນະນຳລະຫັດຜ່ານທີ່ເດົາຍາກ</translation>
 <translation id="1871208020102129563">ພຣັອກຊີໄດ້ຖືກຕັ້ງຂຶ້ນ ເພື່ອໃຊ້ເຊີບເວີພຣັອກຊີທີ່ກໍານົດໄວ້, ບໍ່ແມ່ນ URL ຕົວໜັງສື  .pac.</translation>
 <translation id="1871284979644508959">ຊ່ອງຂໍ້ມູນທີ່ຕ້ອງລະບຸ</translation>
 <translation id="1875512691959384712">Google Forms</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">ປັບໃຫ້ພໍດີ</translation>
 <translation id="2691924980723297736">ຄຳເຕືອນຄວາມປອດໄພ</translation>
-<translation id="2696268945573510710">ໃຊ້ລະຫັດຜ່ານທີ່ເກັບໄວ້ໃນບັນຊີ Google ຂອງທ່ານ</translation>
 <translation id="2699302886720511147">ບັດທີ່ຍອມຮັບ</translation>
 <translation id="2701514975700770343">ຂວ້າມລົງ</translation>
 <translation id="2702801445560668637">ລາຍການທີ່ຈະອ່ານ</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">ການຂັດຂ້ອງເມື່ອ <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">ປິດໂປຣແກຣມອື່ນ</translation>
 <translation id="2922350208395188000">ບໍ່ສາມາດກວດກາໃບຢັ້ງຢືນຂອງເຊີບເວີໄດ້.</translation>
-<translation id="2924027812781652774">ເຂົ້າສູ່ລະບົບເພື່ອໃຊ້ລະຫັດຜ່ານທີ່ເກັບໄວ້ໃນບັນຊີ Google ຂອງທ່ານ</translation>
 <translation id="2925673989565098301">ວິທີການຈັດສົ່ງ</translation>
 <translation id="2928905813689894207">ທີ່ຢູ່ຮຽກເກັບເງິນ</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ແລະ ອີກ <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ທີ່ຢູ່}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ແລະ ອີກ <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ທີ່ຢູ່}}</translation>
diff --git a/components/strings/components_strings_lt.xtb b/components/strings/components_strings_lt.xtb
index 00373f4..3d8858a 100644
--- a/components/strings/components_strings_lt.xtb
+++ b/components/strings/components_strings_lt.xtb
@@ -225,7 +225,6 @@
 <translation id="1838374766361614909">Išvalyti paiešką</translation>
 <translation id="1839551713262164453">Nepavyko patvirtinti politikos verčių (rasta klaidų)</translation>
 <translation id="1842969606798536927">Mokėti</translation>
-<translation id="1852694792039666893">Naudoti „Google“ paskyros siūlomą sudėtingą slaptažodį</translation>
 <translation id="1871208020102129563">Įgaliotasis serveris nustatytas naudoti fiksuotų įgaliotųjų serverių, o ne .pac scenarijaus URL.</translation>
 <translation id="1871284979644508959">Būtinas laukas</translation>
 <translation id="1875512691959384712">„Google“ formos</translation>
@@ -410,7 +409,6 @@
 <translation id="2684561033061424857">11 x 12</translation>
 <translation id="2687555958734450033">Geriausias dydis</translation>
 <translation id="2691924980723297736">Saugos įspėjimas</translation>
-<translation id="2696268945573510710">Naudoti „Google“ paskyroje saugomus slaptažodžius</translation>
 <translation id="2699302886720511147">Tinkamos kortelės</translation>
 <translation id="2701514975700770343">Gerąja puse į apačią</translation>
 <translation id="2702801445560668637">Skait. sąraš.</translation>
@@ -459,7 +457,6 @@
 <translation id="2915068235268646559">Strigtis, įvykusi <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Uždarykite kitas programas</translation>
 <translation id="2922350208395188000">Neįmanoma patikrinti serverio sertifikato.</translation>
-<translation id="2924027812781652774">Prisijunkite, kad galėtumėte naudoti „Google“ paskyroje saugomus slaptažodžius</translation>
 <translation id="2925673989565098301">Pristatymo metodas</translation>
 <translation id="2928905813689894207">Atsiskaitymo adresas</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_lv.xtb b/components/strings/components_strings_lv.xtb
index 3c58c503..52b2128b 100644
--- a/components/strings/components_strings_lv.xtb
+++ b/components/strings/components_strings_lv.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Notīrīt meklēšanas vaicājumu</translation>
 <translation id="1839551713262164453">Politikas vērtību validēšana neizdevās, tika konstatētas kļūdas</translation>
 <translation id="1842969606798536927">Maksāt</translation>
-<translation id="1852694792039666893">Izmantot Google kontu, lai izveidotu drošu paroli</translation>
 <translation id="1871208020102129563">Starpniekserveris ir iestatīts, lai tas lietotu fiksētus starpniekserverus, nevis .pac skripta URL.</translation>
 <translation id="1871284979644508959">Obligātais lauks</translation>
 <translation id="1875512691959384712">Google veidlapas</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Optimāla ietilpināšana</translation>
 <translation id="2691924980723297736">Drošības brīdinājums</translation>
-<translation id="2696268945573510710">Izmantot jūsu Google kontā saglabātās paroles</translation>
 <translation id="2699302886720511147">Atbalstītās kartes</translation>
 <translation id="2701514975700770343">Virspuse uz leju</translation>
 <translation id="2702801445560668637">Atvērt sarakstu</translation>
@@ -456,7 +454,6 @@
 <translation id="2915068235268646559">Avārija no: <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Aizveriet citas programmas</translation>
 <translation id="2922350208395188000">Servera sertifikātu nevar pārbaudīt.</translation>
-<translation id="2924027812781652774">Pierakstieties, lai izmantotu savā Google kontā saglabātās paroles</translation>
 <translation id="2925673989565098301">Piegādes veids</translation>
 <translation id="2928905813689894207">Norēķinu adrese</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> un vēl <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}zero{<ph name="SHIPPING_ADDRESS_PREVIEW" /> un vēl <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> un vēl <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> un vēl <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_mk.xtb b/components/strings/components_strings_mk.xtb
index 6822c17b..d2df2d3 100644
--- a/components/strings/components_strings_mk.xtb
+++ b/components/strings/components_strings_mk.xtb
@@ -206,10 +206,10 @@
 <translation id="1763864636252898013">Серверот не можеше да докаже дека е <ph name="DOMAIN" />; oперативниот систем на уредот не му верува на неговиот безбедносен сертификат. Тоа може да се должи на погрешна конфигурација или на напаѓач што го пресретнува поврзувањето.</translation>
 <translation id="1768211456781949159"><ph name="BEGIN_LINK" />Обидете се да извршите дијагностика на мрежата на Windows<ph name="END_LINK" />.</translation>
 <translation id="1772163372082567643">Серверот каде што сте упатени, <ph name="ORIGIN" />, поставил наслов
-    со кој се бара примена на политика за потекло за сите барања до него. Но,
+    со кој се бара примена на правило за потекло за сите барања до него. Но,
     насловот е лошо форматиран, што го спречува прелистувачот да го исполни
-    вашето барање за <ph name="SITE" />. Политиките за потекло може да се користат од страна на
-     операторите на сајтови за конфигурирање на безбедноста и другите својства за сајтот.</translation>
+    вашето барање за <ph name="SITE" />. Операторите на сајтови може да ги користат правилата за потекло
+     за конфигурирање на безбедноста и другите својства за сајтот.</translation>
 <translation id="1778646502362731194">JIS B0</translation>
 <translation id="1783075131180517613">Ажурирајте ја вашата лозинка за синхронизирање.</translation>
 <translation id="1787142507584202372">Отворените картички се појавуваат тука</translation>
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Исчисти го пребарувањето</translation>
 <translation id="1839551713262164453">Проверката на вредностите на правилото не успеа поради грешки</translation>
 <translation id="1842969606798536927">Плати</translation>
-<translation id="1852694792039666893">Користете ја сметката на Google за да се предложи силна лозинка</translation>
 <translation id="1871208020102129563">Прокси е поставен да користи фиксни прокси-сервери, а не ПАК-скрипта на URL.</translation>
 <translation id="1871284979644508959">Задолжително поле</translation>
 <translation id="1875512691959384712">Формулари на Google</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Најдобро вклопување</translation>
 <translation id="2691924980723297736">Безбедносно предупредување</translation>
-<translation id="2696268945573510710">Користете лозинки складирани во вашата сметка на Google</translation>
 <translation id="2699302886720511147">Прифатени картички</translation>
 <translation id="2701514975700770343">Со лицето надолу</translation>
 <translation id="2702801445560668637">Список за читање</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Пад од <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Затворете ги другите програми</translation>
 <translation id="2922350208395188000">Не може да се провери сертификатот на серверот.</translation>
-<translation id="2924027812781652774">Најавете се за да користите лозинки складирани во вашата сметка на Google</translation>
 <translation id="2925673989565098301">Начин на испорака</translation>
 <translation id="2928905813689894207">Адреса за наплата</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и уште <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и уште <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и уште <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
@@ -711,8 +708,8 @@
     Ако сметате дека ова ви се прикажува по грешка, одете на https://bugs.chromium.org/p/chromium/issues/entry?template=Safety+Tips+Appeals.</translation>
 <translation id="3987940399970879459">Помалку од 1 MB</translation>
 <translation id="3990250421422698716">Офсет превиткување</translation>
-<translation id="3996311196211510766">Сајтот <ph name="ORIGIN" /> побарал да се применува политика за потекло
-     за сите барања до него, но оваа политика не може да се примени во моментов.</translation>
+<translation id="3996311196211510766">Сајтот <ph name="ORIGIN" /> побарал да се применува правило за потекло
+     за сите барања до него, но ова правило не може да се примени во моментов.</translation>
 <translation id="40103911065039147">{URL_count,plural, =1{1 веб-страница во близина}one{# веб-страница во близина}other{# веб-страници во близина}}</translation>
 <translation id="4014128326099193693">{COUNT,plural, =1{PDF-документ со {COUNT} страница}one{PDF-документ со {COUNT} страница}other{PDF-документ со {COUNT} страници}}</translation>
 <translation id="4030383055268325496">&amp;Врати додавање</translation>
@@ -758,9 +755,9 @@
 <translation id="4196861286325780578">&amp;Повтори преместување</translation>
 <translation id="4203896806696719780"><ph name="BEGIN_LINK" />Да ги проверите заштитниот ѕид и антивирусните конфигурации<ph name="END_LINK" /></translation>
 <translation id="4209166701302774460">Серверот каде што сте упатени, <ph name="ORIGIN" />, побарал
-    да се применува политика за потекло за сите барања до него. Но, сега не успеа
-    да испорача политика, што го спречува прелистувачот да го исполни вашето барање
-    за <ph name="SITE" />. Политиките за потекло може да се користат од страна на операторите на сајтови
+    да се применува правило за потекло за сите барања до него. Но, сега не успеа
+    да испорача правило, што го спречува прелистувачот да го исполни вашето барање
+    за <ph name="SITE" />. Операторите на сајтови може да ги користат правилата за потекло
     за конфигурирање на безбедноста и другите својства за сајтот.</translation>
 <translation id="421066178035138955">да ги користи уредите и податоците за виртуелна реалност</translation>
 <translation id="4214357935346142455">профил на екранот за најавување</translation>
@@ -1252,7 +1249,7 @@
 <translation id="6259156558325130047">&amp;Повтори прередување</translation>
 <translation id="6263376278284652872"><ph name="DOMAIN" /> обележувачи</translation>
 <translation id="6264485186158353794">Назад во безбедност</translation>
-<translation id="6265794661083428563">Копирај ја вредноста на политиката <ph name="POLICY_NAME" /></translation>
+<translation id="6265794661083428563">Копирај ја вредноста на правилото <ph name="POLICY_NAME" /></translation>
 <translation id="6266934640124581640">Светла синозелена</translation>
 <translation id="6272383483618007430">Ажурирање на Google</translation>
 <translation id="6276112860590028508">Страниците од списокот за читање се појавуваат тука</translation>
diff --git a/components/strings/components_strings_ml.xtb b/components/strings/components_strings_ml.xtb
index f3530ade..c5d038e 100644
--- a/components/strings/components_strings_ml.xtb
+++ b/components/strings/components_strings_ml.xtb
@@ -223,7 +223,6 @@
 <translation id="1838374766361614909">തിരയൽ മായ്ക്കുക</translation>
 <translation id="1839551713262164453">നയ മൂല്യങ്ങളുടെ സാധൂകരണം പിശകുകളോടെ പരാജയപ്പെട്ടു</translation>
 <translation id="1842969606798536927">പണമടയ്‌ക്കുക</translation>
-<translation id="1852694792039666893">ശക്തമായ പാസ്‌വേഡ് നിർദ്ദേശിക്കാൻ നിങ്ങളുടെ Google അക്കൗണ്ട് ഉപയോഗിക്കുക</translation>
 <translation id="1871208020102129563">സ്ഥിരമായ പ്രോക്‌സി സെർവറുകൾ ഉപയോഗിക്കുന്നതിനായി പ്രോക്‌സി സജ്ജീകരിച്ചിരിക്കുന്നു, ഒരു .pac സ്‌ക്രിപ്റ്റ് URL ഉപയോഗിക്കുന്നതിനല്ല.</translation>
 <translation id="1871284979644508959">ഇത് പൂരിപ്പിക്കേണ്ടതുണ്ട്</translation>
 <translation id="1875512691959384712">Google ഫോം</translation>
@@ -408,7 +407,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">ഏറ്റവും അനുയോജ്യമായത്</translation>
 <translation id="2691924980723297736">സുരക്ഷാ മുന്നറിയിപ്പ്</translation>
-<translation id="2696268945573510710">നിങ്ങളുടെ Google അക്കൗണ്ടിൽ സംഭരിച്ചിരിക്കുന്ന പാസ്‌വേഡുകൾ ഉപയോഗിക്കുക</translation>
 <translation id="2699302886720511147">സ്വീകരിക്കുന്ന കാർഡുകൾ</translation>
 <translation id="2701514975700770343">ഫേസ് ഡൗൺ</translation>
 <translation id="2702801445560668637">വായനാ ലിസ്റ്റ്</translation>
@@ -455,7 +453,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" /> മുതൽ ക്രാഷ് ആയി</translation>
 <translation id="2916038427272391327">മറ്റ് പ്രോഗ്രാമുകൾ അടയ്‌ക്കുക</translation>
 <translation id="2922350208395188000">സെർവറിന്റെ സർട്ടിഫിക്കറ്റ് പരിശോധിക്കാനാകുന്നില്ല.</translation>
-<translation id="2924027812781652774">നിങ്ങളുടെ Google അക്കൗണ്ടിൽ സംഭരിച്ചിരിക്കുന്ന പാസ്‌വേഡുകൾ ഉപയോഗിക്കാൻ സൈൻ ഇൻ ചെയ്യുക</translation>
 <translation id="2925673989565098301">ഡെലിവറി രീതി</translation>
 <translation id="2928905813689894207">ബില്ലിംഗ് വിലാസം</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> എന്നതും മറ്റ് <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> എണ്ണവും}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> എന്നതും മറ്റ് <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> എണ്ണവും}}</translation>
diff --git a/components/strings/components_strings_mn.xtb b/components/strings/components_strings_mn.xtb
index db615e6..0368a63 100644
--- a/components/strings/components_strings_mn.xtb
+++ b/components/strings/components_strings_mn.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Хайлтыг арилгах</translation>
 <translation id="1839551713262164453">Удирдамжийн утгыг баталгаажуулахад алдаа гарч, амжилтгүй боллоо</translation>
 <translation id="1842969606798536927">Төлөх</translation>
-<translation id="1852694792039666893">Сайн нууц үг санал болгохын тулд Google Бүртгэлээ ашиглах</translation>
 <translation id="1871208020102129563">Төлөөлөх сервер нь a .pac script URL биш харин тухайлан сонгосон төлөөлөх сервер ашиглах тохиргоотой байдаг.</translation>
 <translation id="1871284979644508959">Заавал бөглөх хэсэг</translation>
 <translation id="1875512691959384712">Google Маягт</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Хамгийн оновтой тохирол</translation>
 <translation id="2691924980723297736">Аюулгүй байдлын анхааруулга</translation>
-<translation id="2696268945573510710">Google Бүртгэлдээ хадгалсан нууц үгийг ашиглах</translation>
 <translation id="2699302886720511147">Зөвшөөрсөн карт</translation>
 <translation id="2701514975700770343">Нүүрээр нь доош харуулсан</translation>
 <translation id="2702801445560668637">Унших жагсаалт</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" />-н гэмтэл</translation>
 <translation id="2916038427272391327">Бусад хөтөлбөрийг хаах</translation>
 <translation id="2922350208395188000">Серверийн гэрчилгээг шалгаж болохгүй байна.</translation>
-<translation id="2924027812781652774">Google Бүртгэлдээ хадгалсан нууц үгийг ашиглахын тулд нэвтэрнэ үү</translation>
 <translation id="2925673989565098301">Хүргэлтийн төрөл</translation>
 <translation id="2928905813689894207">Тооцооны хаяг</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> болон бусад <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> болон бусад <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_mr.xtb b/components/strings/components_strings_mr.xtb
index 3bb3a11..1eaecd7 100644
--- a/components/strings/components_strings_mr.xtb
+++ b/components/strings/components_strings_mr.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">शोध साफ करा</translation>
 <translation id="1839551713262164453">धोरण मूल्यांची वैधता एररसह अयशस्वी झाली आहे</translation>
 <translation id="1842969606798536927">पेमेंट करा</translation>
-<translation id="1852694792039666893">क्लिष्ट पासवर्ड सुचवण्यासाठी तुमचे Google खाते वापरा</translation>
 <translation id="1871208020102129563">प्रॉक्सी निश्चित प्रॉक्सी सर्व्हर वापरण्‍यास सेट करण्‍यात आले आहे, .pac स्क्रिप्ट URL नव्हे.</translation>
 <translation id="1871284979644508959">या जागा भरणे आवश्यक</translation>
 <translation id="1875512691959384712">Google फॉर्म</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">सर्वोत्तम फिट</translation>
 <translation id="2691924980723297736">सुरक्षा चेतावणी</translation>
-<translation id="2696268945573510710">तुमच्या Google खाते मध्ये स्टोअर केलेले पासवर्ड वापरा</translation>
 <translation id="2699302886720511147">स्वीकारली जाणारी कार्डे</translation>
 <translation id="2701514975700770343">फेस डाउन</translation>
 <translation id="2702801445560668637">वाचन सूची</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" /> पासून क्रॅश</translation>
 <translation id="2916038427272391327">अन्य प्रोग्राम बंद करा</translation>
 <translation id="2922350208395188000">सर्व्हरचे सर्टिफिकेट तपासणे शक्य नाही.</translation>
-<translation id="2924027812781652774">तुमच्या Google खाते मध्ये स्टोअर केलेले पासवर्ड वापरण्यासाठी साइन इन करा</translation>
 <translation id="2925673989565098301">वितरण पद्धत</translation>
 <translation id="2928905813689894207">बिलिंग पत्ता</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> आणि <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> आणखी}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> आणि <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> आणखी}}</translation>
diff --git a/components/strings/components_strings_ms.xtb b/components/strings/components_strings_ms.xtb
index 09bf5126..4e9d793 100644
--- a/components/strings/components_strings_ms.xtb
+++ b/components/strings/components_strings_ms.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Kosongkan carian</translation>
 <translation id="1839551713262164453">Pengesahan nilai dasar gagal dengan ralat</translation>
 <translation id="1842969606798536927">Bayar</translation>
-<translation id="1852694792039666893">Gunakan Akaun Google anda untuk mencadangkan kata laluan kukuh</translation>
 <translation id="1871208020102129563">Proksi ditetapkan untuk menggunakan pelayan proksi tetap, bukannya URL skrip .pac.</translation>
 <translation id="1871284979644508959">Medan yang diperlukan</translation>
 <translation id="1875512691959384712">Borang Google</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Paling sesuai</translation>
 <translation id="2691924980723297736">Amaran keselamatan</translation>
-<translation id="2696268945573510710">Gunakan kata laluan yang disimpan dalam Akaun Google anda</translation>
 <translation id="2699302886720511147">Kad yang Diterima</translation>
 <translation id="2701514975700770343">Menghadap ke bawah</translation>
 <translation id="2702801445560668637">Senarai Bacaan</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Ranap sistem dari <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Tutup atur cara lain</translation>
 <translation id="2922350208395188000">Sijil pelayan tidak boleh diperiksa.</translation>
-<translation id="2924027812781652774">Log masuk untuk menggunakan kata laluan yang disimpan dalam Akaun Google anda</translation>
 <translation id="2925673989565098301">Kaedah Penghantaran</translation>
 <translation id="2928905813689894207">Alamat Pengebilan</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> dan <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> lagi}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> dan <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> lagi}}</translation>
diff --git a/components/strings/components_strings_my.xtb b/components/strings/components_strings_my.xtb
index a4e6da5..2bc07b1 100644
--- a/components/strings/components_strings_my.xtb
+++ b/components/strings/components_strings_my.xtb
@@ -226,7 +226,6 @@
 <translation id="1838374766361614909">ရှာဖွေမှုကို ရှင်းပါ</translation>
 <translation id="1839551713262164453">မူဝါဒတန်ဖိုးများကို အတည်ပြုရာတွင် အမှားအယွင်းရှိနေသည်</translation>
 <translation id="1842969606798536927">ငွေပေးချေရန်</translation>
-<translation id="1852694792039666893">လုံခြုံမှုမြင့်သည့် စကားဝှက် အကြံပြုရန်အတွက် သင့် Google Account ကို အသုံးပြုရန်</translation>
 <translation id="1871208020102129563">ပရောက်စီအား တိကျသည့် ပရောက်ဟီဆာဗာများ သတ်မှတ်ထားသည်၊ .pac script URL မဟုတ်ပါ။</translation>
 <translation id="1871284979644508959">ဖြည့်ရန်လိုအပ်သည့်အကွက်</translation>
 <translation id="1875512691959384712">Google Forms</translation>
@@ -411,7 +410,6 @@
 <translation id="2684561033061424857">၁၁x၁၂</translation>
 <translation id="2687555958734450033">အကောင်းဆုံး အံကိုက်ညှိရန်</translation>
 <translation id="2691924980723297736">ဘေးကင်းလုံခြုံမှုဆိုင်ရာ သတိပေးချက်</translation>
-<translation id="2696268945573510710">သင့် Google Account တွင် သိမ်းထားသောစကားဝှက်များ အသုံးပြုရန်</translation>
 <translation id="2699302886720511147">အသုံးပြုနိုင်သည့် ကတ်များ</translation>
 <translation id="2701514975700770343">မှောက်ထားရန်</translation>
 <translation id="2702801445560668637">ဖတ်ရန် စာရင်း</translation>
@@ -460,7 +458,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" /> မှ ရပ်တန့်သွားမှု</translation>
 <translation id="2916038427272391327">အခြား ပရိုဂရမ်များကို ပိတ်ပါ</translation>
 <translation id="2922350208395188000">ဆာဗာ၏ လက်မှတ် စစ်၍မရပါ။</translation>
-<translation id="2924027812781652774">သင့် Google Account တွင် သိမ်းထားသောစကားဝှက်များ အသုံးပြုရန် လက်မှတ်ထိုးဝင်ပါ</translation>
 <translation id="2925673989565098301">ပို့ရန် နည်းလမ်း</translation>
 <translation id="2928905813689894207">ငွေတောင်းခံလွှာပို့ရန် လိပ်စာ</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> နှင့် နောက်ထပ် <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> နှင့် နောက်ထပ် <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_ne.xtb b/components/strings/components_strings_ne.xtb
index 173dae6..c0ff69f 100644
--- a/components/strings/components_strings_ne.xtb
+++ b/components/strings/components_strings_ne.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">खोजी खाली गर्नुहोस्</translation>
 <translation id="1839551713262164453">त्रुटिले गर्दा नीतिका मानहरू प्रमाणीकरण गर्न सकिएन</translation>
 <translation id="1842969606798536927">भुक्तानी गर्नुहोस्</translation>
-<translation id="1852694792039666893">एउटा भरपर्दो पासवर्ड सिफारिस गर्न आफ्नो Google खाता प्रयोग गर्नुहोस्</translation>
 <translation id="1871208020102129563">प्रोक्सी निश्चित प्रोक्सी सर्भर प्रयोग गर्न सेट गरिएको छ, .pac स्क्रिप्ट युआरएल होइन।</translation>
 <translation id="1871284979644508959">आवश्यक क्षेत्र</translation>
 <translation id="1875512691959384712">Google फारम</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">सबैभन्दा मिल्ने</translation>
 <translation id="2691924980723297736">सुरक्षासम्बन्धी चेतावनी</translation>
-<translation id="2696268945573510710">आफ्नो Google खातामा भण्डारण गरिएका पासवर्डहरू प्रयोग गर्नुहोस्</translation>
 <translation id="2699302886720511147">स्वीकार गरिने कार्डहरू</translation>
 <translation id="2701514975700770343">तलतिर फर्केको</translation>
 <translation id="2702801445560668637">पाठ्य सूची</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" /> मा भएको क्र्यास</translation>
 <translation id="2916038427272391327">अन्य प्रोग्रामहरू बन्द गर्नुहोस्</translation>
 <translation id="2922350208395188000">सर्भरको प्रमाणपत्र जाँच गर्न सकिँदैन।</translation>
-<translation id="2924027812781652774">आफ्नो Google खातामा भण्डारण गरिएका पासवर्डहरू प्रयोग गर्न साइन इन गर्नुहोस्</translation>
 <translation id="2925673989565098301">डेलिभरीको विधि</translation>
 <translation id="2928905813689894207">बिलिङ ठेगाना</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> र थप <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> र थप <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_nl.xtb b/components/strings/components_strings_nl.xtb
index 2067661..bef4961 100644
--- a/components/strings/components_strings_nl.xtb
+++ b/components/strings/components_strings_nl.xtb
@@ -221,7 +221,6 @@
 <translation id="1838374766361614909">Zoekopdracht wissen</translation>
 <translation id="1839551713262164453">De validatie van de beleidswaarden is mislukt doordat er fouten zijn opgetreden</translation>
 <translation id="1842969606798536927">Betalen</translation>
-<translation id="1852694792039666893">Je Google-account gebruiken om een sterk wachtwoord voor te stellen</translation>
 <translation id="1871208020102129563">Proxy is ingesteld op het gebruik van vaste proxyservers, niet op een script-URL van het PAC-type.</translation>
 <translation id="1871284979644508959">Verplicht veld</translation>
 <translation id="1875512691959384712">Google Formulieren</translation>
@@ -406,7 +405,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Best passend</translation>
 <translation id="2691924980723297736">Veiligheidswaarschuwing</translation>
-<translation id="2696268945573510710">Wachtwoorden gebruiken die zijn opgeslagen in je Google-account</translation>
 <translation id="2699302886720511147">Geaccepteerde passen</translation>
 <translation id="2701514975700770343">Bedrukte zijde omlaag</translation>
 <translation id="2702801445560668637">Leeslijst</translation>
@@ -453,7 +451,6 @@
 <translation id="2915068235268646559">Crash van <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Andere programma's sluiten</translation>
 <translation id="2922350208395188000">Het servercertificaat kan niet worden gecontroleerd.</translation>
-<translation id="2924027812781652774">Inloggen om wachtwoorden te gebruiken die zijn opgeslagen in je Google-account</translation>
 <translation id="2925673989565098301">Bezorgingsmethode</translation>
 <translation id="2928905813689894207">Factuuradres</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> en nog <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> en nog <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_no.xtb b/components/strings/components_strings_no.xtb
index 8861f54..80fcc05 100644
--- a/components/strings/components_strings_no.xtb
+++ b/components/strings/components_strings_no.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Fjern søket</translation>
 <translation id="1839551713262164453">Validering av regelverdier mislyktes med feil</translation>
 <translation id="1842969606798536927">Betal</translation>
-<translation id="1852694792039666893">Bruk Google-kontoen din til å foreslå et sterkt passord</translation>
 <translation id="1871208020102129563">Mellomtjeneren er angitt til å bruke statiske proxytjenere, ikke en nettadresse med .pac-skript.</translation>
 <translation id="1871284979644508959">Obligatorisk felt</translation>
 <translation id="1875512691959384712">Google Skjemaer</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Beste tilpassing</translation>
 <translation id="2691924980723297736">Sikkerhetsadvarsel</translation>
-<translation id="2696268945573510710">Bruk passord som er lagret i Google-kontoen din</translation>
 <translation id="2699302886720511147">Godkjente kort</translation>
 <translation id="2701514975700770343">Forsiden ned</translation>
 <translation id="2702801445560668637">Leseliste</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Krasj fra <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Lukk andre programmer</translation>
 <translation id="2922350208395188000">Tjenerens sertifikat kan ikke kontrolleres.</translation>
-<translation id="2924027812781652774">Logg på for å bruke passord som er lagret i Google-kontoen din</translation>
 <translation id="2925673989565098301">Leveringsmåte</translation>
 <translation id="2928905813689894207">Faktureringsadresse</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> til}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> til}}</translation>
diff --git a/components/strings/components_strings_or.xtb b/components/strings/components_strings_or.xtb
index 39ed2d0..236c354 100644
--- a/components/strings/components_strings_or.xtb
+++ b/components/strings/components_strings_or.xtb
@@ -220,7 +220,6 @@
 <translation id="1838374766361614909">ସନ୍ଧାନ ଖାଲି କରନ୍ତୁ</translation>
 <translation id="1839551713262164453">ତ୍ରୁଟିଗୁଡ଼ିକ ସହିତ ନୀତିଗତ ମୂଲ୍ୟଗୁଡ଼ିକର ବୈଧକରଣ ବିଫଳ ହୋଇଛି</translation>
 <translation id="1842969606798536927">ପେମେଣ୍ଟ କରନ୍ତୁ</translation>
-<translation id="1852694792039666893">ଏକ ଜଟିଳ ପାସୱାର୍ଡର ପ୍ରସ୍ତାବ ଦେବାକୁ ଆପଣଙ୍କ Google ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରନ୍ତୁ</translation>
 <translation id="1871208020102129563">ପ୍ରକ୍ସି ନିର୍ଦ୍ଦିଷ୍ଟ କରାଯାଇଥିବା ପ୍ରକ୍ସି ସର୍ଭର୍‌ଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବାକୁ ସେଟ୍ କରାଯାଇଛି, ଏକ .pac ସ୍କ୍ରିପ୍ଟ URLକୁ ନୁହେଁ।</translation>
 <translation id="1871284979644508959">ଆବଶ୍ୟକୀୟ ଫିଲ୍ଡ</translation>
 <translation id="1875512691959384712">Google ଫର୍ମ</translation>
@@ -405,7 +404,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">ଉତ୍ତମ ଫିଟ୍</translation>
 <translation id="2691924980723297736">ସୁରକ୍ଷା ଚେତାବନୀ</translation>
-<translation id="2696268945573510710">ଆପଣଙ୍କ Google ଆକାଉଣ୍ଟରେ ଷ୍ଟୋର୍ କରାଯାଇଥିବା ପାସୱାର୍ଡଗୁଡ଼ିକ ବ୍ୟବହାର କରନ୍ତୁ</translation>
 <translation id="2699302886720511147">ସ୍ୱୀକାର କରାଯାଇଥିବା କାର୍ଡ</translation>
 <translation id="2701514975700770343">ଫେସ୍ ଡାଉନ୍</translation>
 <translation id="2702801445560668637">ପଢ଼ିବା ତାଲିକା</translation>
@@ -452,7 +450,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" />ରେ କ୍ରାସ୍ ହୋଇଛି</translation>
 <translation id="2916038427272391327">ଅନ୍ୟ ପ୍ରୋଗ୍ରାମ୍‌ଗୁଡ଼ିକ ବନ୍ଦ କରନ୍ତୁ</translation>
 <translation id="2922350208395188000">ସର୍ଭରର ସାର୍ଟିଫିକେଟ୍‌ ଯାଞ୍ଚ କରିହେବ ନାହିଁ</translation>
-<translation id="2924027812781652774">ଆପଣଙ୍କ Google ଆକାଉଣ୍ଟରେ ଷ୍ଟୋର୍ କରାଯାଇଥିବା ପାସୱାର୍ଡଗୁଡ଼ିକ ବ୍ୟବହାର କରିବାକୁ ସାଇନ୍ ଇନ୍ କରନ୍ତୁ</translation>
 <translation id="2925673989565098301">ବିତରଣ ପଦ୍ଧତି</translation>
 <translation id="2928905813689894207">ବିଲିଂ ଠିକଣା</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ଏବଂ ଅଧିକ<ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />ଟି}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ଏବଂ ଅଧିକ <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />ଟି}}</translation>
diff --git a/components/strings/components_strings_pa.xtb b/components/strings/components_strings_pa.xtb
index a95e3eb9..ebeafa2 100644
--- a/components/strings/components_strings_pa.xtb
+++ b/components/strings/components_strings_pa.xtb
@@ -220,7 +220,6 @@
 <translation id="1838374766361614909">ਖੋਜ ਹਟਾਓ</translation>
 <translation id="1839551713262164453">ਨੀਤੀ ਮੁੱਲਾਂ ਦਾ ਪ੍ਰਮਾਣੀਕਰਨ ਗੜਬੜਾਂ ਦੇ ਕਾਰਨ ਅਸਫਲ ਰਿਹਾ</translation>
 <translation id="1842969606798536927">ਭੁਗਤਾਨ ਕਰੋ</translation>
-<translation id="1852694792039666893">ਮਜ਼ਬੂਤ ਪਾਸਵਰਡ ਦਾ ਸੁਝਾਅ ਦੇਣ ਲਈ ਆਪਣੇ Google ਖਾਤੇ ਦੀ ਵਰਤੋਂ ਕਰੋ</translation>
 <translation id="1871208020102129563">ਪ੍ਰੌਕਸੀ ਸਥਿਰ ਪ੍ਰੌਕਸੀ ਸਰਵਰ ਵਰਤਣ ਲਈ ਸੈੱਟ ਹੈ, ਇੱਕ .pac ਸਕ੍ਰਿਪਟ URL ਨਹੀਂ।</translation>
 <translation id="1871284979644508959">ਲੋੜੀਂਦਾ ਖੇਤਰ</translation>
 <translation id="1875512691959384712">Google ਫ਼ਾਰਮ</translation>
@@ -405,7 +404,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">ਪੂਰੀ ਤਰ੍ਹਾਂ ਫਿੱਟ</translation>
 <translation id="2691924980723297736">ਸੁਰੱਖਿਆ ਚਿਤਾਵਨੀ</translation>
-<translation id="2696268945573510710">ਆਪਣੇ Google ਖਾਤੇ ਵਿੱਚ ਸਟੋਰ ਕੀਤੇ ਪਾਸਵਰਡ ਵਰਤੋ</translation>
 <translation id="2699302886720511147">ਮਨਜ਼ੂਰਸ਼ੁਦਾ ਕਾਰਡ</translation>
 <translation id="2701514975700770343">ਹੇਠਾਂ ਵੱਲ ਪਾਸਾ ਕੀਤੇ</translation>
 <translation id="2702801445560668637">ਵਾਚਣ ਸੂਚੀ</translation>
@@ -453,7 +451,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" /> ਤੋਂ ਕ੍ਰੈਸ਼</translation>
 <translation id="2916038427272391327">ਦੂਜੇ ਪ੍ਰੋਗਰਾਮ ਬੰਦ ਕਰੋ</translation>
 <translation id="2922350208395188000">ਸਰਵਰ ਦੇ ਪ੍ਰਮਾਣ-ਪੱਤਰ ਦੀ ਜਾਂਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।</translation>
-<translation id="2924027812781652774">ਆਪਣੇ Google ਖਾਤੇ ਵਿੱਚ ਸਟੋਰ ਕੀਤੇ ਪਾਸਵਰਡ ਵਰਤਣ ਲਈ ਸਾਈਨ-ਇਨ ਕਰੋ</translation>
 <translation id="2925673989565098301">ਡਿਲਿਵਰੀ ਵਿਧੀ</translation>
 <translation id="2928905813689894207">ਬਿਲਿੰਗ ਪਤਾ</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ਅਤੇ <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ਹੋਰ}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ਅਤੇ <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ਹੋਰ}}</translation>
diff --git a/components/strings/components_strings_pl.xtb b/components/strings/components_strings_pl.xtb
index 070adce2..1961d9d 100644
--- a/components/strings/components_strings_pl.xtb
+++ b/components/strings/components_strings_pl.xtb
@@ -220,7 +220,6 @@
 <translation id="1838374766361614909">Wyczyść wyszukiwanie</translation>
 <translation id="1839551713262164453">Weryfikacja wartości zasad nie udała się z powodu błędów</translation>
 <translation id="1842969606798536927">Zapłać</translation>
-<translation id="1852694792039666893">Użyj konta Google do wygenerowania silnego hasła</translation>
 <translation id="1871208020102129563">Proxy skonfigurowano do używania stałych serwerów proxy, a nie URL-a skryptu PAC.</translation>
 <translation id="1871284979644508959">Pole wymagane</translation>
 <translation id="1875512691959384712">Formularze Google</translation>
@@ -405,7 +404,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Najlepsze dopasowanie</translation>
 <translation id="2691924980723297736">Ostrzeżenie zabezpieczeń</translation>
-<translation id="2696268945573510710">Użyj haseł zapisanych na koncie Google</translation>
 <translation id="2699302886720511147">Akceptowane karty</translation>
 <translation id="2701514975700770343">W dół</translation>
 <translation id="2702801445560668637">Do przeczytania</translation>
@@ -454,7 +452,6 @@
 <translation id="2915068235268646559">Awaria od <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Zamknij inne programy</translation>
 <translation id="2922350208395188000">Nie można sprawdzić certyfikatu serwera.</translation>
-<translation id="2924027812781652774">Zaloguj się, by używać haseł zapisanych na Twoim koncie Google</translation>
 <translation id="2925673989565098301">Metoda dostawy</translation>
 <translation id="2928905813689894207">Adres rozliczeniowy</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i jeszcze <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i jeszcze <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i jeszcze <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i jeszcze <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_pt-BR.xtb b/components/strings/components_strings_pt-BR.xtb
index b6ad7f65..4a6fa95 100644
--- a/components/strings/components_strings_pt-BR.xtb
+++ b/components/strings/components_strings_pt-BR.xtb
@@ -221,7 +221,6 @@
 <translation id="1838374766361614909">Limpar pesquisa</translation>
 <translation id="1839551713262164453">Falha com erros na validação dos valores da política</translation>
 <translation id="1842969606798536927">Pagar</translation>
-<translation id="1852694792039666893">Usar sua Conta do Google para sugerir uma senha forte</translation>
 <translation id="1871208020102129563">O proxy foi configurado para utilizar servidores de proxy fixo e não um URL de script .pac.</translation>
 <translation id="1871284979644508959">Campo obrigatório</translation>
 <translation id="1875512691959384712">Formulários Google</translation>
@@ -406,7 +405,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Melhor ajuste</translation>
 <translation id="2691924980723297736">Alerta de segurança</translation>
-<translation id="2696268945573510710">Usar senhas armazenadas na Conta do Google</translation>
 <translation id="2699302886720511147">Cartões aceitos</translation>
 <translation id="2701514975700770343">Virada para baixo</translation>
 <translation id="2702801445560668637">Lista de leitura</translation>
@@ -453,7 +451,6 @@
 <translation id="2915068235268646559">Falha a partir de <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Fechar outros programas</translation>
 <translation id="2922350208395188000">O certificado do servidor não pode ser verificado.</translation>
-<translation id="2924027812781652774">Faça login para usar as senhas armazenadas na sua Conta do Google</translation>
 <translation id="2925673989565098301">Método de envio</translation>
 <translation id="2928905813689894207">Endereço de cobrança</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_pt-PT.xtb b/components/strings/components_strings_pt-PT.xtb
index 36af383..a6f2b0ca 100644
--- a/components/strings/components_strings_pt-PT.xtb
+++ b/components/strings/components_strings_pt-PT.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Limpar pesquisa</translation>
 <translation id="1839551713262164453">A validação dos valores da política falhou devido a erros.</translation>
 <translation id="1842969606798536927">Pagar</translation>
-<translation id="1852694792039666893">Utilizar a sua Conta Google para sugerir uma palavra-passe forte</translation>
 <translation id="1871208020102129563">O proxy está definido para utilizar servidores proxy fixos e não um URL de script .pac.</translation>
 <translation id="1871284979644508959">Campo obrigatório</translation>
 <translation id="1875512691959384712">Google Forms</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Tamanho otimizado</translation>
 <translation id="2691924980723297736">Aviso de segurança</translation>
-<translation id="2696268945573510710">Utilizar palavras-passe armazenadas na sua Conta Google</translation>
 <translation id="2699302886720511147">Cartões aceites</translation>
 <translation id="2701514975700770343">Com orientação para baixo</translation>
 <translation id="2702801445560668637">Lista de leitura</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Falha de sistema de <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Fechar outros programas</translation>
 <translation id="2922350208395188000">Não é possível verificar o certificado do servidor.</translation>
-<translation id="2924027812781652774">Inicie sessão para utilizar palavras-passe armazenadas na sua Conta Google</translation>
 <translation id="2925673989565098301">Método de fornecimento</translation>
 <translation id="2928905813689894207">Endereço de faturação</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_ro.xtb b/components/strings/components_strings_ro.xtb
index e40a1774..1b54941e 100644
--- a/components/strings/components_strings_ro.xtb
+++ b/components/strings/components_strings_ro.xtb
@@ -225,7 +225,6 @@
 <translation id="1838374766361614909">Șterge căutarea</translation>
 <translation id="1839551713262164453">Validarea valorilor de politică a returnat erori</translation>
 <translation id="1842969606798536927">Plătește</translation>
-<translation id="1852694792039666893">Folosește Contul Google ca să sugerezi o parolă puternică</translation>
 <translation id="1871208020102129563">Configurația proxy este setată să utilizeze servere proxy fixe, și nu o adresă URL pentru scripturi .pac.</translation>
 <translation id="1871284979644508959">Câmp obligatoriu</translation>
 <translation id="1875512691959384712">Formulare Google</translation>
@@ -410,7 +409,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Potrivire optimă</translation>
 <translation id="2691924980723297736">Avertisment de siguranță</translation>
-<translation id="2696268945573510710">Folosește parolele stocate în Contul Google</translation>
 <translation id="2699302886720511147">Carduri acceptate</translation>
 <translation id="2701514975700770343">Cu fața în jos</translation>
 <translation id="2702801445560668637">Listă de lectură</translation>
@@ -457,7 +455,6 @@
 <translation id="2915068235268646559">Blocare survenită <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">închide celelalte programe;</translation>
 <translation id="2922350208395188000">Certificatul serverului nu poate fi verificat.</translation>
-<translation id="2924027812781652774">Conectează-te pentru a folosi parolele stocate în Contul Google</translation>
 <translation id="2925673989565098301">Metodă de livrare</translation>
 <translation id="2928905813689894207">Adresă de facturare</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> și încă <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> și încă <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> și încă <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_ru.xtb b/components/strings/components_strings_ru.xtb
index 7527cd4..7b70563 100644
--- a/components/strings/components_strings_ru.xtb
+++ b/components/strings/components_strings_ru.xtb
@@ -220,7 +220,6 @@
 <translation id="1838374766361614909">Удалить условия поиска</translation>
 <translation id="1839551713262164453">При проверке значений политик обнаружены ошибки</translation>
 <translation id="1842969606798536927">Оплатить</translation>
-<translation id="1852694792039666893">Использовать аккаунт Google, чтобы сгенерировать надежный пароль</translation>
 <translation id="1871208020102129563">Выбрано использование фиксированных прокси-серверов, а не URL PAC-скрипта.</translation>
 <translation id="1871284979644508959">Поле, обязательное для заполнения</translation>
 <translation id="1875512691959384712">Google Формы</translation>
@@ -405,7 +404,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Оптимальный вариант</translation>
 <translation id="2691924980723297736">Предупреждение</translation>
-<translation id="2696268945573510710">Использовать пароли, хранящиеся в аккаунте Google</translation>
 <translation id="2699302886720511147">Карты, которые принимаются к оплате</translation>
 <translation id="2701514975700770343">Лицевой стороной вниз</translation>
 <translation id="2702801445560668637">Список для чтения</translation>
@@ -452,7 +450,6 @@
 <translation id="2915068235268646559">Дата и время сбоя: <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Закройте другие программы.</translation>
 <translation id="2922350208395188000">Не удается проверить сертификат сервера.</translation>
-<translation id="2924027812781652774">Чтобы использовать пароли, сохраненные в аккаунте Google, выполните вход</translation>
 <translation id="2925673989565098301">Способ доставки</translation>
 <translation id="2928905813689894207">Платежный адрес</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> адрес}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> адрес}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> адреса}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> адресов}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> адреса}}</translation>
diff --git a/components/strings/components_strings_si.xtb b/components/strings/components_strings_si.xtb
index 1a91915f..2910607 100644
--- a/components/strings/components_strings_si.xtb
+++ b/components/strings/components_strings_si.xtb
@@ -225,7 +225,6 @@
 <translation id="1838374766361614909">සෙවීම හිස් කරන්න</translation>
 <translation id="1839551713262164453">ප්‍රතිපත්ති අගයන්ගේ වලංගු කිරීම දෝෂ සමග අසමත් වී ඇත</translation>
 <translation id="1842969606798536927">ගෙවන්න</translation>
-<translation id="1852694792039666893">ප්‍රබල මුරපදයක් යෝජනා කිරීමට ඔබේ Google ගිණුම භාවිත කරන්න</translation>
 <translation id="1871208020102129563">.pac ස්ක්‍රිප්ට URL එතත් නොව, ස්ථාවර ප්‍රොක්සි සේවාදයක භාවිතා කිරීමට ප්‍රොක්සි සකසා ඇත,</translation>
 <translation id="1871284979644508959">අවශ්‍ය ක්ෂේත්‍රය</translation>
 <translation id="1875512691959384712">Google පෝරම</translation>
@@ -410,7 +409,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">හොඳින්ම ගැළපේ</translation>
 <translation id="2691924980723297736">ආරක්‍ෂක අවවාදය</translation>
-<translation id="2696268945573510710">ඔබේ Google ගිණුම තුළ ගබඩා කර ඇති මුරපද භාවිත කරන්න</translation>
 <translation id="2699302886720511147">පිළිගත් කාඩ්පත්</translation>
 <translation id="2701514975700770343">මුහුණ පහළට</translation>
 <translation id="2702801445560668637">කියවීම් ලැයිස්තුව</translation>
@@ -457,7 +455,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" /> වෙතින් බිඳ වැටීම්</translation>
 <translation id="2916038427272391327">අනෙකුත් වැඩසටහන් වසන්න</translation>
 <translation id="2922350208395188000">සේවාදායකයේ සහතිකය සහතික කළ නොහැක</translation>
-<translation id="2924027812781652774">ඔබේ Google ගිණුම තුළ ගබඩා කර ඇති මුරපද භාවිත කිරීමට පුරන්න</translation>
 <translation id="2925673989565098301">බෙදා හැරීමේ ක්‍රමය</translation>
 <translation id="2928905813689894207">බිල්පත් ලිපිනය</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> සහ තව <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> සහ තව <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> සහ තව <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_sk.xtb b/components/strings/components_strings_sk.xtb
index 6368865..ad8a4e9 100644
--- a/components/strings/components_strings_sk.xtb
+++ b/components/strings/components_strings_sk.xtb
@@ -220,7 +220,6 @@
 <translation id="1838374766361614909">Vymazať vyhľadávanie</translation>
 <translation id="1839551713262164453">Overenie hodnôt pravidiel zlyhalo a obsahuje chyby</translation>
 <translation id="1842969606798536927">Zaplatiť</translation>
-<translation id="1852694792039666893">Vygenerujte si silné heslo pomocou účtu Google</translation>
 <translation id="1871208020102129563">Proxy je nastavené na použitie pevne daných serverov proxy, nie skriptov PAC webovej adresy.</translation>
 <translation id="1871284979644508959">Povinné pole</translation>
 <translation id="1875512691959384712">Formuláre Google</translation>
@@ -405,7 +404,6 @@
 <translation id="2684561033061424857">11 x 12</translation>
 <translation id="2687555958734450033">Prispôsobená veľkosť</translation>
 <translation id="2691924980723297736">Bezpečnostné upozornenie</translation>
-<translation id="2696268945573510710">Použiť heslá uložené vo vašom účte Google</translation>
 <translation id="2699302886720511147">Akceptované karty</translation>
 <translation id="2701514975700770343">Lícom nadol</translation>
 <translation id="2702801445560668637">Čitateľský zoznam</translation>
@@ -452,7 +450,6 @@
 <translation id="2915068235268646559">Zrútenie v čase <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Zavrite ostatné programy</translation>
 <translation id="2922350208395188000">Certifikát servera sa nedá overiť.</translation>
-<translation id="2924027812781652774">Prihlásiť sa a používať heslá uložené vo vašom účte Google</translation>
 <translation id="2925673989565098301">Spôsob doručenia</translation>
 <translation id="2928905813689894207">Fakturačná adresa</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ďalšia}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ďalšie}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ďalšej}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ďalších}}</translation>
diff --git a/components/strings/components_strings_sl.xtb b/components/strings/components_strings_sl.xtb
index aea1846..8dd23d9 100644
--- a/components/strings/components_strings_sl.xtb
+++ b/components/strings/components_strings_sl.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Čiščenje iskanja</translation>
 <translation id="1839551713262164453">Preverjanje vrednosti pravilnika je bilo neuspešno z napakami</translation>
 <translation id="1842969606798536927">Plačilo</translation>
-<translation id="1852694792039666893">Uporabite račun Google za predlaganje zapletenega gesla</translation>
 <translation id="1871208020102129563">Proxy je nastavljen na uporabo stalnih strežnikov proxy, ne na URL skripta .pac.</translation>
 <translation id="1871284979644508959">Obvezno polje</translation>
 <translation id="1875512691959384712">Google Obrazci</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Najustreznejše</translation>
 <translation id="2691924980723297736">Varnostno opozorilo</translation>
-<translation id="2696268945573510710">Uporabite gesla, shranjena v računu Google</translation>
 <translation id="2699302886720511147">Sprejete kartice</translation>
 <translation id="2701514975700770343">Z licem navzdol</translation>
 <translation id="2702801445560668637">Reading List</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Zrušitev: <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Zaprite druge programe</translation>
 <translation id="2922350208395188000">Potrdila strežnika ni mogoče preveriti.</translation>
-<translation id="2924027812781652774">Prijavite se, če želite uporabljati gesla, shranjena v računu Google.</translation>
 <translation id="2925673989565098301">Način dostave</translation>
 <translation id="2928905813689894207">Naslov za izstavitev računa</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}two{<ph name="SHIPPING_ADDRESS_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_sq.xtb b/components/strings/components_strings_sq.xtb
index 0810e86..77be38f 100644
--- a/components/strings/components_strings_sq.xtb
+++ b/components/strings/components_strings_sq.xtb
@@ -178,6 +178,7 @@
 <translation id="1671391448414634642">Faqet në <ph name="SOURCE_LANGUAGE" /> do të përkthehen në <ph name="TARGET_LANGUAGE" /> nga tani e në vazhdim.</translation>
 <translation id="1676269943528358898"><ph name="SITE" /> përdor zakonisht enkriptimin për mbrojtjen e informacioneve të tua. Kur Google Chrome u përpoq të lidhej me <ph name="SITE" /> këtë herë, sajti i uebit dërgoi prapa kredenciale të pazakonta dhe të pasakta. Kjo mund të ndodhë kur një sulmues pretendon se është <ph name="SITE" /> ose kur lidhja është ndërprerë nga një ekran i identifikimit të Wi-Fi. Informacionet e tua janë ende të sigurta sepse Google Chrome e ndaloi lidhjen para se të shkëmbeheshin të dhënat.</translation>
 <translation id="1682696192498422849">Ana e shkurtër në fillim</translation>
+<translation id="168693727862418163">Vërtetimi i kësaj vlere të politikës kundrejt skemës së saj dështoi dhe do të shpërfillet.</translation>
 <translation id="168841957122794586">Certifikata e serverit përmban një çelës të dobët kriptografik.</translation>
 <translation id="1697532407822776718">Je gati!</translation>
 <translation id="1703835215927279855">Letter</translation>
@@ -206,7 +207,7 @@
 <translation id="1763864636252898013">Ky server nuk mundi të dëshmonte se ky është <ph name="DOMAIN" />; certifikata e tij e sigurisë nuk është e besueshme nga Chromium. Kjo mund të shkaktohet nga keqkonfigurimi ose ndonjë sulmues që po kap lidhjen tënde.</translation>
 <translation id="1768211456781949159"><ph name="BEGIN_LINK" />Provo të ekzekutosh diagnostikimin e rrjetit të Windows<ph name="END_LINK" />.</translation>
 <translation id="1772163372082567643">Serveri ku po shkon, <ph name="ORIGIN" />, ka vendosur një titull
-    që kërkon që të aplikohet një politikë origjine për të gjitha kërkesat për të. Por
+    që kërkon që të aplikohet një politikë origjine për të gjitha kërkesat drejtuar atij. Por
     titulli është formuar gabimisht, gjë që e parandalon përmbushjen e
     kërkesës sate për <ph name="SITE" />. Politikat e origjinës mund të përdoren nga operatorët e sajtit për të konfiguruar karakteristikat e sigurisë dhe karakteristika të tjera për një sajt.</translation>
 <translation id="1778646502362731194">JIS B0</translation>
@@ -223,7 +224,6 @@
 <translation id="1838374766361614909">Fshi kërkimin</translation>
 <translation id="1839551713262164453">Vërtetimi i vlerave të politikës ka dështuar me gabime</translation>
 <translation id="1842969606798536927">Paguaj</translation>
-<translation id="1852694792039666893">Përdor "Llogarinë tënde të Google" për të sugjeruar një fjalëkalim të fortë</translation>
 <translation id="1871208020102129563">Përfaqësuesi është caktuar të përdorë serverë përfaqësues fiksë, jo një shkrim URL-je .pac.</translation>
 <translation id="1871284979644508959">Fushë e detyrueshme</translation>
 <translation id="1875512691959384712">Formularët e Google</translation>
@@ -408,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Përshtatja më e mirë</translation>
 <translation id="2691924980723297736">Paralajmërimi i sigurisë</translation>
-<translation id="2696268945573510710">Përdor fjalëkalimet e ruajtura në "Llogarinë tënde të Google"</translation>
 <translation id="2699302886720511147">Kartat e pranuara</translation>
 <translation id="2701514975700770343">E kthyer poshtë</translation>
 <translation id="2702801445560668637">Lista e leximit</translation>
@@ -455,7 +454,6 @@
 <translation id="2915068235268646559">Ndërprerje aksidentale nga <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Mbyll programet e tjera</translation>
 <translation id="2922350208395188000">Certifikata e serverit nuk mund të kontrollohet.</translation>
-<translation id="2924027812781652774">Identifikohu për të përdorur fjalëkalimet e ruajtura në "Llogarinë tënde të Google"</translation>
 <translation id="2925673989565098301">Mënyra e dorëzimit</translation>
 <translation id="2928905813689894207">Adresa e faturimit</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> dhe <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> tjetër}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> dhe <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> të tjera}}</translation>
@@ -709,7 +707,7 @@
 <translation id="3987940399970879459">Më pak se 1 MB</translation>
 <translation id="3990250421422698716">Zhvendosja e bordurës</translation>
 <translation id="3996311196211510766">Sajti <ph name="ORIGIN" /> ka kërkuar që të zbatohet një politikë e origjinës
-    për të gjitha kërkesat e tij, por kjo politikë nuk mund të zbatohet aktualisht.</translation>
+    për të gjitha kërkesat drejtuar atij, por kjo politikë nuk mund të zbatohet aktualisht.</translation>
 <translation id="40103911065039147">{URL_count,plural, =1{1 faqe uebi në afërsi}other{# faqe uebi në afërsi}}</translation>
 <translation id="4014128326099193693">{COUNT,plural, =1{Dokumenti PDF me {COUNT} faqe}other{Dokumenti PDF me {COUNT} faqe}}</translation>
 <translation id="4030383055268325496">&amp;Zhbëje shtimin</translation>
@@ -754,7 +752,7 @@
 <translation id="4194250254487269611">Karta jote nuk mund të ruhet për momentin</translation>
 <translation id="4196861286325780578">&amp;Bëje përsëri zhvendosjen</translation>
 <translation id="4203896806696719780"><ph name="BEGIN_LINK" />Të kontrollosh konfigurimet e murit mbrojtës dhe antivirusit<ph name="END_LINK" /></translation>
-<translation id="4209166701302774460">Serveri ku po shkon, <ph name="ORIGIN" />, ka kërkuar që të zbatohet një politikë e origjinës për të gjitha kërkesat për të. Por tani nuk ka arritur
+<translation id="4209166701302774460">Serveri ku po shkon, <ph name="ORIGIN" />, ka kërkuar që të zbatohet një politikë e origjinës për të gjitha kërkesat drejtuar atij Por tani nuk ka arritur
     të dorëzojë një politikë, gjë që parandalon që shfletuesi të përmbushë kërkesën tënde për <ph name="SITE" />. Politikat e origjinës mund të përdoren nga operatorët
     e sajtit për të konfiguruar karakteristikat e sigurisë dhe karakteristika të tjera për një sajt.</translation>
 <translation id="421066178035138955">Përdor pajisjet dhe të dhënat e "Realitetit virtual"</translation>
diff --git a/components/strings/components_strings_sr-Latn.xtb b/components/strings/components_strings_sr-Latn.xtb
index dbdc2da0..a5297b5 100644
--- a/components/strings/components_strings_sr-Latn.xtb
+++ b/components/strings/components_strings_sr-Latn.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Obrišite pretragu</translation>
 <translation id="1839551713262164453">Validacija vrednosti smernica nije uspela uz greške</translation>
 <translation id="1842969606798536927">Plati</translation>
-<translation id="1852694792039666893">Upotrebite Google nalog za predlaganje jake lozinke</translation>
 <translation id="1871208020102129563">Proksi je podešen da koristi fiksne proksi servere, a ne URL adresu .pac skripte.</translation>
 <translation id="1871284979644508959">Obavezno polje</translation>
 <translation id="1875512691959384712">Google upitnici</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Najbolja veličina</translation>
 <translation id="2691924980723297736">Bezbednosno upozorenje</translation>
-<translation id="2696268945573510710">Koristite lozinke koje se čuvaju na Google nalogu</translation>
 <translation id="2699302886720511147">Kartice koje se prihvataju</translation>
 <translation id="2701514975700770343">Sa odštampanom stranom nadole</translation>
 <translation id="2702801445560668637">Lista za čitanje</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Izveštaj o otkazivanju od <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Zatvorite druge programe</translation>
 <translation id="2922350208395188000">Nije moguće proveriti sertifikat servera.</translation>
-<translation id="2924027812781652774">Prijavite se da biste koristili lozinke sačuvane na Google nalogu</translation>
 <translation id="2925673989565098301">Način isporuke</translation>
 <translation id="2928905813689894207">Adresa za obračun</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_sr.xtb b/components/strings/components_strings_sr.xtb
index 6d4bb6e..e476399 100644
--- a/components/strings/components_strings_sr.xtb
+++ b/components/strings/components_strings_sr.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Обришите претрагу</translation>
 <translation id="1839551713262164453">Валидација вредности смерница није успела уз грешке</translation>
 <translation id="1842969606798536927">Плати</translation>
-<translation id="1852694792039666893">Употребите Google налог за предлагање јаке лозинке</translation>
 <translation id="1871208020102129563">Прокси је подешен да користи фиксне прокси сервере, а не URL адресу .pac скрипте.</translation>
 <translation id="1871284979644508959">Обавезно поље</translation>
 <translation id="1875512691959384712">Google упитници</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Најбоља величина</translation>
 <translation id="2691924980723297736">Безбедносно упозорење</translation>
-<translation id="2696268945573510710">Користите лозинке које се чувају на Google налогу</translation>
 <translation id="2699302886720511147">Картице које се прихватају</translation>
 <translation id="2701514975700770343">Са одштампаном страном надоле</translation>
 <translation id="2702801445560668637">Листа за читање</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Извештај о отказивању од <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Затворите друге програме</translation>
 <translation id="2922350208395188000">Није могуће проверити сертификат сервера.</translation>
-<translation id="2924027812781652774">Пријавите се да бисте користили лозинке сачуване на Google налогу</translation>
 <translation id="2925673989565098301">Начин испоруке</translation>
 <translation id="2928905813689894207">Адреса за обрачун</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и још <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и још <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и још <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и још <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_sv.xtb b/components/strings/components_strings_sv.xtb
index 1cd990e2..a07b249 100644
--- a/components/strings/components_strings_sv.xtb
+++ b/components/strings/components_strings_sv.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Rensa sökning</translation>
 <translation id="1839551713262164453">Valideringen av principvärdena har misslyckats med fel</translation>
 <translation id="1842969606798536927">Betala</translation>
-<translation id="1852694792039666893">Använd Google-kontot till att generera ett starkt lösenord</translation>
 <translation id="1871208020102129563">Proxyn är inställd på att använda fasta proxyservrar, inte en webbadress med PAC-skript.</translation>
 <translation id="1871284979644508959">Obligatoriskt fält</translation>
 <translation id="1875512691959384712">Google Formulär</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Bästa passning</translation>
 <translation id="2691924980723297736">Säkerhetsvarning</translation>
-<translation id="2696268945573510710">Använd lösenord som har sparats i Google-kontot</translation>
 <translation id="2699302886720511147">Godkända kort</translation>
 <translation id="2701514975700770343">Framsidan nedåt</translation>
 <translation id="2702801445560668637">Läslista</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Krasch från <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Stäng andra program</translation>
 <translation id="2922350208395188000">Servercertifikatet kan inte kontrolleras.</translation>
-<translation id="2924027812781652774">Logga in om du vill använda lösenord som har sparats i Google-kontot</translation>
 <translation id="2925673989565098301">Leveranssätt</translation>
 <translation id="2928905813689894207">Faktureringsadress</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> och <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> till}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> och <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> till}}</translation>
diff --git a/components/strings/components_strings_sw.xtb b/components/strings/components_strings_sw.xtb
index 0873fb9..5c26df04 100644
--- a/components/strings/components_strings_sw.xtb
+++ b/components/strings/components_strings_sw.xtb
@@ -178,6 +178,7 @@
 <translation id="1671391448414634642">Itatafsiri kurasa za <ph name="SOURCE_LANGUAGE" /> katika <ph name="TARGET_LANGUAGE" /> kuanzia sasa.</translation>
 <translation id="1676269943528358898">Kwa kawaida <ph name="SITE" /> hutumia usimbaji fiche ili kulinda maelezo yako. Google Chrome ilipojaribu kuunganisha kwenye <ph name="SITE" /> wakati huu, tovuti ilituma kitambulisho kisicho cha kawaida na kisicho sahihi. Hili linaweza kutokea mvamizi anapojaribu kujifanya kuwa <ph name="SITE" />, au uchanganuzi wa kuingia katika Wi-Fi umeingilia muunganisho. Maelezo yako yangali salama kwa sababu Google Chrome ilisimamisha muunganisho kabla data yoyote itumwe.</translation>
 <translation id="1682696192498422849">Pembe fupi kwanza</translation>
+<translation id="168693727862418163">Thamani ya sera hii imeshindwa kuthibitishwa kwenye taratibu yake na itapuuzwa.</translation>
 <translation id="168841957122794586">Cheti cha seva kina kitufe dhaifu cha kifichua msimbo.</translation>
 <translation id="1697532407822776718">Mko tayari nyote!</translation>
 <translation id="1703835215927279855">Barua</translation>
@@ -223,7 +224,6 @@
 <translation id="1838374766361614909">Futa utafutaji</translation>
 <translation id="1839551713262164453">Imeshindwa kuthibitisha thamani za sera kutokana na hitilafu</translation>
 <translation id="1842969606798536927">Lipa</translation>
-<translation id="1852694792039666893">Tumia Akaunti yako ya Google kutunga nenosiri thabiti</translation>
 <translation id="1871208020102129563">Proksi imewekwa ili kutumia seva za proksi thabiti, siyo URL ya hati .pac.</translation>
 <translation id="1871284979644508959">Lazima sehemu hii ijazwe</translation>
 <translation id="1875512691959384712">Fomu za Google</translation>
@@ -408,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Itoshee vizuri</translation>
 <translation id="2691924980723297736">Onyo la usalama</translation>
-<translation id="2696268945573510710">Tumia manenosiri uliyohifadhi kwenye Akaunti yako ya Google</translation>
 <translation id="2699302886720511147">Kadi Zinazokubaliwa</translation>
 <translation id="2701514975700770343">Inayoangalia chini</translation>
 <translation id="2702801445560668637">Orodha ya Kusoma</translation>
@@ -457,7 +456,6 @@
 <translation id="2915068235268646559">Ripoti ya programu kuacha kufanya kazi kuanzia <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Funga programu nyingine</translation>
 <translation id="2922350208395188000">Cheti cha seva hakiwezi kukaguliwa.</translation>
-<translation id="2924027812781652774">Ingia katika akaunti ili utumie manenosiri uliyohifadhi kwenye Akaunti yako ya Google</translation>
 <translation id="2925673989565098301">Njia ya Kusafirisha</translation>
 <translation id="2928905813689894207">Anwani ya kutuma Bili</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> na nyingine <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> na nyingine <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_ta.xtb b/components/strings/components_strings_ta.xtb
index 14d8870..41d42d2 100644
--- a/components/strings/components_strings_ta.xtb
+++ b/components/strings/components_strings_ta.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">தேடலை அழி</translation>
 <translation id="1839551713262164453">கொள்கை மதிப்புகளின் சரிபார்ப்பு பிழைகளுடன் தோல்வியில் முடிந்தது.</translation>
 <translation id="1842969606798536927">பணம் செலுத்துக</translation>
-<translation id="1852694792039666893">Google கணக்கைப் பயன்படுத்தி வலிமையான கடவுச்சொல்லைப் பரிந்துரைக்கவும்</translation>
 <translation id="1871208020102129563">நிலையான ப்ராக்ஸி சேவையகங்களைப் பயன்படுத்த ப்ராக்ஸி அமைக்கப்பட்டுள்ளது, .pac ஸ்கிரிப்ட் URL அல்ல.</translation>
 <translation id="1871284979644508959">அவசியமானவை</translation>
 <translation id="1875512691959384712">Google படிவங்கள்</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">கச்சிதமாகப் பொருந்தும் அளவு</translation>
 <translation id="2691924980723297736">பாதுகாப்பு எச்சரிக்கை</translation>
-<translation id="2696268945573510710">உங்கள் Google கணக்கில் சேமிக்கப்பட்டுள்ள கடவுச்சொற்களைப் பயன்படுத்தவும்</translation>
 <translation id="2699302886720511147">ஏற்கப்படும் கார்டுகள்</translation>
 <translation id="2701514975700770343">கீழ் நோக்கியது</translation>
 <translation id="2702801445560668637">வாசிப்புப் பட்டியல்</translation>
@@ -456,7 +454,6 @@
 <translation id="2915068235268646559">சிதைவு அறிக்கை பெறப்பட்ட நேரம்: <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">பிற நிரல்களை மூடவும்</translation>
 <translation id="2922350208395188000">சேவையகச் சான்றிதழை சோதிக்க முடியவில்லை.</translation>
-<translation id="2924027812781652774">உங்கள் Google கணக்கில் சேமிக்கப்பட்டுள்ள கடவுச்சொற்களைப் பயன்படுத்த, உள்நுழையவும்</translation>
 <translation id="2925673989565098301">டெலிவரி முறை</translation>
 <translation id="2928905813689894207">பில்லிங் முகவரி</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" />, மேலும் <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" />, மேலும் <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_te.xtb b/components/strings/components_strings_te.xtb
index b4b66d4..3eb6ab0 100644
--- a/components/strings/components_strings_te.xtb
+++ b/components/strings/components_strings_te.xtb
@@ -226,7 +226,6 @@
 <translation id="1838374766361614909">శోధనను తీసివేయి</translation>
 <translation id="1839551713262164453">విధాన విలువల క్రమబద్ధీకరణ ఎర్రర్‌లతో విఫలమైంది</translation>
 <translation id="1842969606798536927">చెల్లింపు</translation>
-<translation id="1852694792039666893">శక్తివంతమైన పాస్‌వర్డ్‌ను సూచించడానికి మీ Google ఖాతాను ఉపయోగించండి</translation>
 <translation id="1871208020102129563">.pac స్క్రిప్ట్ URLను కాకుండా, స్థిరమైన ప్రాక్సీ సర్వర్‌లను ఉపయోగించేలా ప్రాక్సీ సెట్ చేయబడింది.</translation>
 <translation id="1871284979644508959">అవసరమైన ఫీల్డ్</translation>
 <translation id="1875512691959384712">Google ఫారమ్‌లు</translation>
@@ -411,7 +410,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">సరిపోయేలా అమర్చు</translation>
 <translation id="2691924980723297736">భద్రతా హెచ్చరిక</translation>
-<translation id="2696268945573510710">మీ Google ఖాతాలో స్టోర్ చేయబడిన పాస్‌వర్డ్‌లను ఉపయోగించండి</translation>
 <translation id="2699302886720511147">ఆమోదించే కార్డ్‌లు</translation>
 <translation id="2701514975700770343">ఫేస్ డౌన్</translation>
 <translation id="2702801445560668637">పఠనా జాబితా</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" /> సమయంలో ఏర్పడిన క్రాష్</translation>
 <translation id="2916038427272391327">ఇతర ప్రోగ్రామ్‌లను మూసివేయండి</translation>
 <translation id="2922350208395188000">సర్వర్ యొక్క ప్రమాణపత్రం తనిఖీ చెయ్యబడదు.</translation>
-<translation id="2924027812781652774">మీ Google ఖాతాలో స్టోర్ చేయబడిన పాస్‌వర్డ్‌లను ఉపయోగించడానికి సైన్ ఇన్ చేయండి</translation>
 <translation id="2925673989565098301">బట్వాడా పద్ధతి</translation>
 <translation id="2928905813689894207">బిల్లింగ్ చిరునామా</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> మరియు మరో <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> మరియు మరో <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_th.xtb b/components/strings/components_strings_th.xtb
index af115a9..5ff4e46 100644
--- a/components/strings/components_strings_th.xtb
+++ b/components/strings/components_strings_th.xtb
@@ -178,6 +178,7 @@
 <translation id="1671391448414634642">จากนี้ไประบบจะแปลหน้าภาษา<ph name="SOURCE_LANGUAGE" />เป็นภาษา<ph name="TARGET_LANGUAGE" /></translation>
 <translation id="1676269943528358898">โดยทั่วไป <ph name="SITE" /> จะใช้การเข้ารหัสเพื่อปกป้องข้อมูลของคุณ เมื่อ Google Chrome พยายามเชื่อมต่อกับ <ph name="SITE" /> ในครั้งนี้ เว็บไซต์ดังกล่าวส่งข้อมูลรับรองที่ผิดปกติและไม่ถูกต้องกลับมา เหตุการณ์นี้อาจเกิดขึ้นเมื่อผู้บุกรุกพยายามปลอมเป็น <ph name="SITE" /> หรือหน้าจอการลงชื่อเข้าใช้ Wi-Fi รบกวนการเชื่อมต่อ ข้อมูลของคุณยังปลอดภัยอยู่เนื่องจาก Google Chrome หยุดการเชื่อมต่อก่อนมีการแลกเปลี่ยนข้อมูล</translation>
 <translation id="1682696192498422849">ด้านขอบสั้นก่อน</translation>
+<translation id="168693727862418163">ตรวจสอบค่านโยบายนี้กับสคีมาไม่ได้ ระบบจะเพิกเฉยต่อค่านี้</translation>
 <translation id="168841957122794586">ใบรับรองของเซิร์ฟเวอร์มีคีย์การเข้ารหัสที่ไม่รัดกุม</translation>
 <translation id="1697532407822776718">คุณพร้อมแล้ว!</translation>
 <translation id="1703835215927279855">Letter</translation>
@@ -220,7 +221,6 @@
 <translation id="1838374766361614909">ล้างการค้นหา</translation>
 <translation id="1839551713262164453">การตรวจสอบความถูกต้องของค่านโยบายมีข้อผิดพลาดและล้มเหลว</translation>
 <translation id="1842969606798536927">จ่าย</translation>
-<translation id="1852694792039666893">ใช้บัญชี Google ของคุณเพื่อแนะนำรหัสผ่านที่รัดกุม</translation>
 <translation id="1871208020102129563">พร็อกซีถูกตั้งค่าให้ใช้พร็อกซีเซิร์ฟเวอร์แบบคงที่ ไม่ใช่ URL สคริปต์ .pac</translation>
 <translation id="1871284979644508959">ช่องที่ต้องกรอก</translation>
 <translation id="1875512691959384712">Google ฟอร์ม</translation>
@@ -405,7 +405,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">ปรับพอดี</translation>
 <translation id="2691924980723297736">คำเตือนด้านความปลอดภัย</translation>
-<translation id="2696268945573510710">ใช้รหัสผ่านที่จัดเก็บในบัญชี Google</translation>
 <translation id="2699302886720511147">บัตรที่ยอมรับ</translation>
 <translation id="2701514975700770343">คว่ำหน้าลง</translation>
 <translation id="2702801445560668637">รายการที่จะอ่าน</translation>
@@ -452,7 +451,6 @@
 <translation id="2915068235268646559">การขัดข้องเมื่อ<ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">ปิดโปรแกรมอื่นๆ</translation>
 <translation id="2922350208395188000">ไม่สามารถตรวจสอบใบรับรองของเซิร์ฟเวอร์</translation>
-<translation id="2924027812781652774">ลงชื่อเข้าใช้เพื่อใช้รหัสผ่านที่จัดเก็บในบัญชี Google</translation>
 <translation id="2925673989565098301">วิธีการนำส่งสินค้า</translation>
 <translation id="2928905813689894207">ที่อยู่สำหรับการเรียกเก็บเงิน</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> และอีก <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> รายการ}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> และอีก <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> รายการ}}</translation>
diff --git a/components/strings/components_strings_tr.xtb b/components/strings/components_strings_tr.xtb
index eb789a6..ec29b816 100644
--- a/components/strings/components_strings_tr.xtb
+++ b/components/strings/components_strings_tr.xtb
@@ -221,7 +221,6 @@
 <translation id="1838374766361614909">Aramayı temizle</translation>
 <translation id="1839551713262164453">Politika değerlerini doğrulama işlemi hatalarla başarısız oldu</translation>
 <translation id="1842969606798536927">Ödeme</translation>
-<translation id="1852694792039666893">Güçlü bir şifre oluşturmak için Google Hesabınızı kullanın</translation>
 <translation id="1871208020102129563">Proxy, bir .pac komut dosyası URL'sini değil, sabit proxy sunucuları kullanacak şekilde ayarlanır.</translation>
 <translation id="1871284979644508959">Zorunlu alan</translation>
 <translation id="1875512691959384712">Google Formlar</translation>
@@ -406,7 +405,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">En uygun</translation>
 <translation id="2691924980723297736">Güvenlik uyarısı</translation>
-<translation id="2696268945573510710">Google Hesabınızda kayıtlı şifreleri kullanın</translation>
 <translation id="2699302886720511147">Kabul Edilen Kartlar</translation>
 <translation id="2701514975700770343">Aşağı dönük</translation>
 <translation id="2702801445560668637">Okuma Listesi</translation>
@@ -453,7 +451,6 @@
 <translation id="2915068235268646559">Kilitlenme zamanı: <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Diğer programları kapatın</translation>
 <translation id="2922350208395188000">Sunucunun sertifikası kontrol edilemiyor.</translation>
-<translation id="2924027812781652774">Google Hesabınızda kayıtlı şifreleri kullanmak için oturum açın</translation>
 <translation id="2925673989565098301">Teslimat Yöntemi</translation>
 <translation id="2928905813689894207">Fatura Adresi</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ve <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> adres daha}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ve <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> adres daha}}</translation>
diff --git a/components/strings/components_strings_uk.xtb b/components/strings/components_strings_uk.xtb
index 5708b25..08f62901 100644
--- a/components/strings/components_strings_uk.xtb
+++ b/components/strings/components_strings_uk.xtb
@@ -225,7 +225,6 @@
 <translation id="1838374766361614909">Очистити поле пошуку</translation>
 <translation id="1839551713262164453">Не вдалося перевірити значення правила. Знайдено помилки</translation>
 <translation id="1842969606798536927">Оплатити</translation>
-<translation id="1852694792039666893">Згенерувати надійний пароль в обліковому записі Google</translation>
 <translation id="1871208020102129563">Проксі-сервер налаштовано на використання фіксованих проксі-серверів, а не URL-адреси сценарію .pac.</translation>
 <translation id="1871284979644508959">Обов’язкове поле</translation>
 <translation id="1875512691959384712">Google Форми</translation>
@@ -410,7 +409,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Оптимальний розмір</translation>
 <translation id="2691924980723297736">Попередження щодо безпеки</translation>
-<translation id="2696268945573510710">Використовувати паролі, збережені в обліковому записі Google</translation>
 <translation id="2699302886720511147">Картки, які приймаються до оплати</translation>
 <translation id="2701514975700770343">Лицевою стороною вниз</translation>
 <translation id="2702801445560668637">Список читання</translation>
@@ -457,7 +455,6 @@
 <translation id="2915068235268646559">Аварійне завершення роботи за <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Закрийте інші програми</translation>
 <translation id="2922350208395188000">Сертифікат сервера неможливо перевірити.</translation>
-<translation id="2924027812781652774">Увійдіть, щоб користуватися паролями, збереженими в обліковому записі Google</translation>
 <translation id="2925673989565098301">Спосіб доставки</translation>
 <translation id="2928905813689894207">Платіжна адреса</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
diff --git a/components/strings/components_strings_ur.xtb b/components/strings/components_strings_ur.xtb
index 54bf3e5..407e878e 100644
--- a/components/strings/components_strings_ur.xtb
+++ b/components/strings/components_strings_ur.xtb
@@ -225,7 +225,6 @@
 <translation id="1838374766361614909">تلاش صاف کریں</translation>
 <translation id="1839551713262164453">پالیسی کی اقدار کی تصدیق خرابیوں کی وجہ سے ناکام ہو گئی</translation>
 <translation id="1842969606798536927">ادائیگی کریں</translation>
-<translation id="1852694792039666893">‏مضبوط پاس ورڈ تجویز کرنے کے لیے اپنا Google اکاؤنٹ استعمال کریں</translation>
 <translation id="1871208020102129563">‏پراکسی ایک ‎.pac اسکرپٹ URL نہیں بلکہ مقررہ پراکسی سرورز استعمال کرنے کیلئے سیٹ ہے۔</translation>
 <translation id="1871284979644508959">مطلوبہ فیلڈ</translation>
 <translation id="1875512691959384712">Google Forms</translation>
@@ -410,7 +409,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">بہترین فٹ</translation>
 <translation id="2691924980723297736">حفاظتی وارننگ</translation>
-<translation id="2696268945573510710">‏اپنے Google اکاؤنٹ میں اسٹور کردہ پاس ورڈز کا استعمال کریں</translation>
 <translation id="2699302886720511147">قبول کردہ کارڈز</translation>
 <translation id="2701514975700770343">نیچے رکھیں</translation>
 <translation id="2702801445560668637">پڑھنے کی فہرست</translation>
@@ -460,7 +458,6 @@
 <translation id="2915068235268646559"><ph name="CRASH_TIME" /> سے ناکامی</translation>
 <translation id="2916038427272391327">دیگر پروگرامز بند کریں</translation>
 <translation id="2922350208395188000">سرور سرٹیفکیٹ کو چیک نہیں کیا جا سکتا ہے۔</translation>
-<translation id="2924027812781652774">‏اپنے Google اکاؤنٹ میں اسٹور کردہ پاس ورڈز کا استعمال کرنے کے لئے سائن ان کریں</translation>
 <translation id="2925673989565098301">ڈیلیوری کا طریقہ</translation>
 <translation id="2928905813689894207">بلنگ پتہ</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> اور <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> مزید}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> اور <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> مزید}}</translation>
diff --git a/components/strings/components_strings_uz.xtb b/components/strings/components_strings_uz.xtb
index affeafb..4338f9d 100644
--- a/components/strings/components_strings_uz.xtb
+++ b/components/strings/components_strings_uz.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Qidiruv shartlarini tozalash</translation>
 <translation id="1839551713262164453">Parametr qiymatlari tekshiruvida xato yuz berdi</translation>
 <translation id="1842969606798536927">To‘lash</translation>
-<translation id="1852694792039666893">Ishonchli parol taklif etish uchun Google hisobingizni ishlating</translation>
 <translation id="1871208020102129563">Proksi-serverlar PAC fayli manzil orqali emas, o‘zgarmas manzil orqali sozlangan.</translation>
 <translation id="1871284979644508959">Kiritilishi shart</translation>
 <translation id="1875512691959384712">Google Forms</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Eng mos</translation>
 <translation id="2691924980723297736">Ogohlantirish</translation>
-<translation id="2696268945573510710">Google hisobingizda saqlangan parollardan foydalaning</translation>
 <translation id="2699302886720511147">Qabul qilinadigan kartalar</translation>
 <translation id="2701514975700770343">Orqa tomonida</translation>
 <translation id="2702801445560668637">Mutolaa ro‘yxati</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Ishdan chiqdi: <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Boshqa dasturlarni yoping</translation>
 <translation id="2922350208395188000">Server sertifikatini tekshirib bo‘lmadi.</translation>
-<translation id="2924027812781652774">Google hisobingizda saqlangan parollardan foydalanish uchun hisobingizga kiring</translation>
 <translation id="2925673989565098301">Yetkazib berish usuli</translation>
 <translation id="2928905813689894207">To‘lov manzili</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> va yana <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ta}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> va yana <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ta}}</translation>
diff --git a/components/strings/components_strings_vi.xtb b/components/strings/components_strings_vi.xtb
index cf597db..db259f79 100644
--- a/components/strings/components_strings_vi.xtb
+++ b/components/strings/components_strings_vi.xtb
@@ -224,7 +224,6 @@
 <translation id="1838374766361614909">Xóa tìm kiếm</translation>
 <translation id="1839551713262164453">Không xác thực được các giá trị của chính sách do xảy ra lỗi</translation>
 <translation id="1842969606798536927">Thanh toán</translation>
-<translation id="1852694792039666893">Sử dụng Tài khoản Google của bạn để tạo mật khẩu mạnh</translation>
 <translation id="1871208020102129563">Proxy được đặt để sử dụng máy chủ proxy cố định chứ không phải URL tập lệnh .pac.</translation>
 <translation id="1871284979644508959">Trường bắt buộc</translation>
 <translation id="1875512691959384712">Google Biểu mẫu</translation>
@@ -409,7 +408,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Phù hợp nhất</translation>
 <translation id="2691924980723297736">Cảnh báo an toàn</translation>
-<translation id="2696268945573510710">Sử dụng mật khẩu lưu trữ trong Tài khoản Google của bạn</translation>
 <translation id="2699302886720511147">Thẻ được chấp nhận</translation>
 <translation id="2701514975700770343">Hướng xuống</translation>
 <translation id="2702801445560668637">Danh sách đọc</translation>
@@ -458,7 +456,6 @@
 <translation id="2915068235268646559">Sự cố từ <ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Đóng các chương trình khác</translation>
 <translation id="2922350208395188000">Không thể kiểm tra chứng chỉ của máy chủ.</translation>
-<translation id="2924027812781652774">Đăng nhập để sử dụng mật khẩu lưu trữ trong Tài khoản Google của bạn</translation>
 <translation id="2925673989565098301">Phương thức giao hàng</translation>
 <translation id="2928905813689894207">Ðịa chỉ thanh toán</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> và <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> địa chỉ giao hàng khác}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> và <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> địa chỉ giao hàng khác}}</translation>
diff --git a/components/strings/components_strings_zh-CN.xtb b/components/strings/components_strings_zh-CN.xtb
index d7a313b..9bff705 100644
--- a/components/strings/components_strings_zh-CN.xtb
+++ b/components/strings/components_strings_zh-CN.xtb
@@ -220,7 +220,6 @@
 <translation id="1838374766361614909">清除搜索字词</translation>
 <translation id="1839551713262164453">由于出现错误,未能成功验证政策值</translation>
 <translation id="1842969606798536927">付款</translation>
-<translation id="1852694792039666893">使用您的 Google 帐号生成一个安全系数高的密码</translation>
 <translation id="1871208020102129563">代理已设置为使用固定的代理服务器,而不是 .pac 脚本网址。</translation>
 <translation id="1871284979644508959">必填字段</translation>
 <translation id="1875512691959384712">Google 表单</translation>
@@ -405,7 +404,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">最适合</translation>
 <translation id="2691924980723297736">安全警告</translation>
-<translation id="2696268945573510710">使用您 Google 帐号中存储的密码</translation>
 <translation id="2699302886720511147">接受的银行卡</translation>
 <translation id="2701514975700770343">正面朝下</translation>
 <translation id="2702801445560668637">读取列表</translation>
@@ -452,7 +450,6 @@
 <translation id="2915068235268646559">崩溃时间:<ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">关闭其他程序</translation>
 <translation id="2922350208395188000">无法核实服务器证书。</translation>
-<translation id="2924027812781652774">登录即可使用您 Google 帐号中存储的密码</translation>
 <translation id="2925673989565098301">递送方式</translation>
 <translation id="2928905813689894207">帐单邮寄地址</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" />以及另外 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> 个地址}other{<ph name="SHIPPING_ADDRESS_PREVIEW" />以及另外 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> 个地址}}</translation>
diff --git a/components/strings/components_strings_zh-HK.xtb b/components/strings/components_strings_zh-HK.xtb
index 74e90797..961114cc 100644
--- a/components/strings/components_strings_zh-HK.xtb
+++ b/components/strings/components_strings_zh-HK.xtb
@@ -220,7 +220,6 @@
 <translation id="1838374766361614909">清除搜尋</translation>
 <translation id="1839551713262164453">發生錯誤,政策值驗證失敗</translation>
 <translation id="1842969606798536927">支付</translation>
-<translation id="1852694792039666893">使用 Google 帳戶建議安全性強的密碼</translation>
 <translation id="1871208020102129563">Proxy 設定為使用固定的 Proxy 伺服器,而非 .pac 指令碼網址。</translation>
 <translation id="1871284979644508959">必填欄位</translation>
 <translation id="1875512691959384712">Google 表格</translation>
@@ -404,7 +403,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">最適合</translation>
 <translation id="2691924980723297736">安全警告</translation>
-<translation id="2696268945573510710">使用儲存在 Google 帳戶中的密碼</translation>
 <translation id="2699302886720511147">接受的付款卡</translation>
 <translation id="2701514975700770343">正面朝下</translation>
 <translation id="2702801445560668637">閱讀清單</translation>
@@ -451,7 +449,6 @@
 <translation id="2915068235268646559">當機時間:<ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">關閉其他程式</translation>
 <translation id="2922350208395188000">無法檢查伺服器憑證。</translation>
-<translation id="2924027812781652774">登入即可使用儲存在 Google 帳戶中的密碼</translation>
 <translation id="2925673989565098301">送貨方式</translation>
 <translation id="2928905813689894207">帳單地址</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{「<ph name="SHIPPING_ADDRESS_PREVIEW" />」和另外 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> 個地址}other{「<ph name="SHIPPING_ADDRESS_PREVIEW" />」和另外 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> 個地址}}</translation>
diff --git a/components/strings/components_strings_zh-TW.xtb b/components/strings/components_strings_zh-TW.xtb
index 1256c8d7..a874c3ab 100644
--- a/components/strings/components_strings_zh-TW.xtb
+++ b/components/strings/components_strings_zh-TW.xtb
@@ -220,7 +220,6 @@
 <translation id="1838374766361614909">清除搜尋</translation>
 <translation id="1839551713262164453">發生錯誤,政策值驗證失敗</translation>
 <translation id="1842969606798536927">支付</translation>
-<translation id="1852694792039666893">使用 Google 帳戶建議高強度密碼</translation>
 <translation id="1871208020102129563">Proxy 設定為使用固定的 Proxy 伺服器,而非 .pac 指令碼網址。</translation>
 <translation id="1871284979644508959">必填欄位</translation>
 <translation id="1875512691959384712">Google 表單</translation>
@@ -405,7 +404,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">最適配置</translation>
 <translation id="2691924980723297736">安全警告</translation>
-<translation id="2696268945573510710">使用儲存在 Google 帳戶中的密碼</translation>
 <translation id="2699302886720511147">接受的卡片</translation>
 <translation id="2701514975700770343">正面朝下</translation>
 <translation id="2702801445560668637">閱讀清單</translation>
@@ -452,7 +450,6 @@
 <translation id="2915068235268646559">當機時間:<ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">關閉其他程式</translation>
 <translation id="2922350208395188000">無法檢查伺服器憑證。</translation>
-<translation id="2924027812781652774">登入即可使用儲存在 Google 帳戶中的密碼</translation>
 <translation id="2925673989565098301">快遞方式</translation>
 <translation id="2928905813689894207">帳單地址</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{「<ph name="SHIPPING_ADDRESS_PREVIEW" />」和另外 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> 個地址}other{「<ph name="SHIPPING_ADDRESS_PREVIEW" />」和另外 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> 個地址}}</translation>
diff --git a/components/strings/components_strings_zu.xtb b/components/strings/components_strings_zu.xtb
index 2d48c27..066dac1 100644
--- a/components/strings/components_strings_zu.xtb
+++ b/components/strings/components_strings_zu.xtb
@@ -178,6 +178,7 @@
 <translation id="1671391448414634642">Amakhasi akusi-<ph name="SOURCE_LANGUAGE" /> azohunyushelwa kusi-<ph name="TARGET_LANGUAGE" /> kusukela manje.</translation>
 <translation id="1676269943528358898">I-<ph name="SITE" /> ngokuvamile isebenzisa ukubethela ukuvikela ulwazi lwakho. Uma i-Google Chrome izame ukuxhuma ku-<ph name="SITE" /> ngalesi sikhathi, iwebhusayithi ithumele emuva imininingwane engavamile nengalungile. Lokhu kungenzeka uma umhlaseli ezama ukuzenza i-<ph name="SITE" />, noma isikrini sokungena se-Wi-Fi siphazamise uxhumo. Ulwazi lwakho lusaphephile ngoba i-Google Chrome imise uxhumo ngaphambi kokuthi idatha ishintshwe.</translation>
 <translation id="1682696192498422849">Umkhawulo omfushane kuqala</translation>
+<translation id="168693727862418163">Ukubaluleka kwale nqubomgomo kuhlulekile ukuqinisekisa ngokumelene ne-schema sayo futhi ngeke inakwe.</translation>
 <translation id="168841957122794586">Isitifiketi seseva siqukethe ukhiye we-cryptographic obuthaka.</translation>
 <translation id="1697532407822776718">Senisethiwe nonke!</translation>
 <translation id="1703835215927279855">Incwadi</translation>
@@ -224,7 +225,6 @@
 <translation id="1838374766361614909">Sula usesho</translation>
 <translation id="1839551713262164453">Ukuqinisekiswa kwamanani enqubomgomo kuhluleke namaphutha</translation>
 <translation id="1842969606798536927">Khokha</translation>
-<translation id="1852694792039666893">Sebenzisa i-akhawunti ye-Google ukuphakamisa iphasiwedi eqinile</translation>
 <translation id="1871208020102129563">Ummeleli usethelwe ukusebenzisa amaseva alibamba agxilile, hhayi i-URL yesikripthi se-.pac</translation>
 <translation id="1871284979644508959">Inkambu edingekayo</translation>
 <translation id="1875512691959384712">Google Amafomu</translation>
@@ -409,7 +409,6 @@
 <translation id="2684561033061424857">11x12</translation>
 <translation id="2687555958734450033">Kulingana kahle kakhulu</translation>
 <translation id="2691924980723297736">Isexwayiso sezokuphepha</translation>
-<translation id="2696268945573510710">Sebenzisa amaphasiwedi agcinwe ku-akhawunti yakho ye-Google</translation>
 <translation id="2699302886720511147">Amakhadi amukelwayo</translation>
 <translation id="2701514975700770343">Bheke phansi</translation>
 <translation id="2702801445560668637">Uhlu lokufunda</translation>
@@ -458,7 +457,6 @@
 <translation id="2915068235268646559">Ukukhubazeka okuvela ku-<ph name="CRASH_TIME" /></translation>
 <translation id="2916038427272391327">Vala ezinye izinhlelo</translation>
 <translation id="2922350208395188000">Isitifiketi seseva asikwazi ukuhlolwa.</translation>
-<translation id="2924027812781652774">Ngena ngemvume ukuze usebenzise amaphasiwedi alondolozwe ku-akhawunti yakho ye-Google</translation>
 <translation id="2925673989565098301">Indlela yokulethwa</translation>
 <translation id="2928905813689894207">Ikheli lokukhokha</translation>
 <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> nongu-<ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ngaphezulu}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> nongu-<ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ngaphezulu}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> nongu-<ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ngaphezulu}}</translation>
diff --git a/components/sync/android/javatests/src/org/chromium/components/sync/AndroidSyncSettingsTest.java b/components/sync/android/javatests/src/org/chromium/components/sync/AndroidSyncSettingsTest.java
index def0bd0f..c14a0345 100644
--- a/components/sync/android/javatests/src/org/chromium/components/sync/AndroidSyncSettingsTest.java
+++ b/components/sync/android/javatests/src/org/chromium/components/sync/AndroidSyncSettingsTest.java
@@ -139,8 +139,7 @@
     }
 
     private void setupTestAccounts() {
-        mAccountManager = new FakeAccountManagerDelegate(
-                FakeAccountManagerDelegate.DISABLE_PROFILE_DATA_SOURCE);
+        mAccountManager = new FakeAccountManagerDelegate();
         ThreadUtils.runOnUiThreadBlocking(() -> {
             AccountManagerFacadeProvider.setInstanceForTests(
                     new AccountManagerFacadeImpl(mAccountManager));
diff --git a/components/sync/driver/fake_sync_service.cc b/components/sync/driver/fake_sync_service.cc
index 15bae7e..9fa381d 100644
--- a/components/sync/driver/fake_sync_service.cc
+++ b/components/sync/driver/fake_sync_service.cc
@@ -54,6 +54,10 @@
   return ModelTypeSet();
 }
 
+ModelTypeSet FakeSyncService::GetBackedOffDataTypes() const {
+  return ModelTypeSet();
+}
+
 void FakeSyncService::AddObserver(SyncServiceObserver* observer) {}
 
 void FakeSyncService::RemoveObserver(SyncServiceObserver* observer) {}
diff --git a/components/sync/driver/fake_sync_service.h b/components/sync/driver/fake_sync_service.h
index 066659e..04d51da 100644
--- a/components/sync/driver/fake_sync_service.h
+++ b/components/sync/driver/fake_sync_service.h
@@ -34,6 +34,7 @@
   bool IsLocalSyncEnabled() const override;
   void TriggerRefresh(const ModelTypeSet& types) override;
   ModelTypeSet GetActiveDataTypes() const override;
+  ModelTypeSet GetBackedOffDataTypes() const override;
   void AddObserver(SyncServiceObserver* observer) override;
   void RemoveObserver(SyncServiceObserver* observer) override;
   bool HasObserver(const SyncServiceObserver* observer) const override;
diff --git a/components/sync/driver/glue/sync_engine_impl.cc b/components/sync/driver/glue/sync_engine_impl.cc
index 58d5bccb..7025357 100644
--- a/components/sync/driver/glue/sync_engine_impl.cc
+++ b/components/sync/driver/glue/sync_engine_impl.cc
@@ -217,7 +217,7 @@
   return backend_->sync_manager()->GetUserShare();
 }
 
-SyncEngineImpl::Status SyncEngineImpl::GetDetailedStatus() {
+const SyncEngineImpl::Status& SyncEngineImpl::GetDetailedStatus() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(IsInitialized());
   return cached_status_;
@@ -420,7 +420,12 @@
 
 void SyncEngineImpl::HandleSyncStatusChanged(const SyncStatus& status) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  const bool backed_off_types_changed =
+      (status.backed_off_types != cached_status_.backed_off_types);
   cached_status_ = status;
+  if (backed_off_types_changed) {
+    host_->OnBackedOffTypesChanged();
+  }
 }
 
 void SyncEngineImpl::OnCookieJarChanged(bool account_mismatch,
diff --git a/components/sync/driver/glue/sync_engine_impl.h b/components/sync/driver/glue/sync_engine_impl.h
index b56ea21f..3d9e751 100644
--- a/components/sync/driver/glue/sync_engine_impl.h
+++ b/components/sync/driver/glue/sync_engine_impl.h
@@ -77,7 +77,7 @@
   void DeactivateProxyDataType(ModelType type) override;
   void EnableEncryptEverything() override;
   UserShare* GetUserShare() const override;
-  Status GetDetailedStatus() override;
+  const Status& GetDetailedStatus() const override;
   void HasUnsyncedItemsForTest(
       base::OnceCallback<void(bool)> cb) const override;
   void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) const override;
@@ -154,7 +154,6 @@
   void UpdateInvalidationVersions(
       const std::map<ModelType, int64_t>& invalidation_versions);
 
-  // Stores the new |status| in local cache.
   void HandleSyncStatusChanged(const SyncStatus& status);
 
  private:
diff --git a/components/sync/driver/mock_sync_service.h b/components/sync/driver/mock_sync_service.h
index 49f40bc..e0cb38a 100644
--- a/components/sync/driver/mock_sync_service.h
+++ b/components/sync/driver/mock_sync_service.h
@@ -48,6 +48,7 @@
   MOCK_CONST_METHOD0(GetRegisteredDataTypes, ModelTypeSet());
   MOCK_CONST_METHOD0(GetPreferredDataTypes, ModelTypeSet());
   MOCK_CONST_METHOD0(GetActiveDataTypes, ModelTypeSet());
+  MOCK_CONST_METHOD0(GetBackedOffDataTypes, ModelTypeSet());
 
   MOCK_METHOD0(StopAndClear, void());
   MOCK_METHOD1(OnDataTypeRequestsSyncStartup, void(ModelType type));
diff --git a/components/sync/driver/profile_sync_service.cc b/components/sync/driver/profile_sync_service.cc
index f3600d9..8ac9f24b 100644
--- a/components/sync/driver/profile_sync_service.cc
+++ b/components/sync/driver/profile_sync_service.cc
@@ -1131,6 +1131,10 @@
   NotifyObservers();
 }
 
+void ProfileSyncService::OnBackedOffTypesChanged() {
+  NotifyObservers();
+}
+
 void ProfileSyncService::OnConfigureDone(
     const DataTypeManager::ConfigureResult& result) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -1347,6 +1351,14 @@
   return data_type_manager_->GetActiveDataTypes();
 }
 
+ModelTypeSet ProfileSyncService::GetBackedOffDataTypes() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (engine_ && engine_->IsInitialized()) {
+    return engine_->GetDetailedStatus().backed_off_types;
+  }
+  return ModelTypeSet();
+}
+
 void ProfileSyncService::SyncAllowedByPlatformChanged(bool allowed) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -1511,7 +1523,7 @@
     return std::move(result);
   }
 
-  SyncStatus detailed_status = engine_->GetDetailedStatus();
+  const SyncStatus& detailed_status = engine_->GetDetailedStatus();
   const ModelTypeSet& throttled_types(detailed_status.throttled_types);
   const ModelTypeSet& backed_off_types(detailed_status.backed_off_types);
 
diff --git a/components/sync/driver/profile_sync_service.h b/components/sync/driver/profile_sync_service.h
index 7cb5a1fe..c442132 100644
--- a/components/sync/driver/profile_sync_service.h
+++ b/components/sync/driver/profile_sync_service.h
@@ -131,6 +131,7 @@
   ModelTypeSet GetRegisteredDataTypes() const override;
   ModelTypeSet GetPreferredDataTypes() const override;
   ModelTypeSet GetActiveDataTypes() const override;
+  ModelTypeSet GetBackedOffDataTypes() const override;
   void StopAndClear() override;
   void OnDataTypeRequestsSyncStartup(ModelType type) override;
   void TriggerRefresh(const ModelTypeSet& types) override;
@@ -184,6 +185,7 @@
   void OnConnectionStatusChange(ConnectionStatus status) override;
   void OnMigrationNeededForTypes(ModelTypeSet types) override;
   void OnActionableError(const SyncProtocolError& error) override;
+  void OnBackedOffTypesChanged() override;
 
   // DataTypeManagerObserver implementation.
   void OnConfigureDone(const DataTypeManager::ConfigureResult& result) override;
diff --git a/components/sync/driver/sync_service.h b/components/sync/driver/sync_service.h
index f27feed..33ddc192 100644
--- a/components/sync/driver/sync_service.h
+++ b/components/sync/driver/sync_service.h
@@ -318,6 +318,10 @@
   // be the empty set. Once the configuration completes the set will be updated.
   virtual ModelTypeSet GetActiveDataTypes() const = 0;
 
+  // Returns the set of currently backed off data types (e.g. returns non-empty
+  // result when the network was disabled during last sync cycle).
+  virtual ModelTypeSet GetBackedOffDataTypes() const = 0;
+
   //////////////////////////////////////////////////////////////////////////////
   // ACTIONS / STATE CHANGE REQUESTS
   //////////////////////////////////////////////////////////////////////////////
diff --git a/components/sync/driver/test_sync_service.cc b/components/sync/driver/test_sync_service.cc
index b65e553..bc585cb 100644
--- a/components/sync/driver/test_sync_service.cc
+++ b/components/sync/driver/test_sync_service.cc
@@ -89,6 +89,10 @@
   active_data_types_ = types;
 }
 
+void TestSyncService::SetBackedOffDataTypes(const ModelTypeSet& types) {
+  backed_off_data_types_ = types;
+}
+
 void TestSyncService::SetLastCycleSnapshot(const SyncCycleSnapshot& snapshot) {
   last_cycle_snapshot_ = snapshot;
 }
@@ -206,6 +210,10 @@
   return active_data_types_;
 }
 
+ModelTypeSet TestSyncService::GetBackedOffDataTypes() const {
+  return backed_off_data_types_;
+}
+
 void TestSyncService::StopAndClear() {}
 
 void TestSyncService::OnDataTypeRequestsSyncStartup(ModelType type) {}
diff --git a/components/sync/driver/test_sync_service.h b/components/sync/driver/test_sync_service.h
index caa44e76..3bf59f7 100644
--- a/components/sync/driver/test_sync_service.h
+++ b/components/sync/driver/test_sync_service.h
@@ -38,6 +38,7 @@
   void SetFirstSetupComplete(bool first_setup_complete);
   void SetPreferredDataTypes(const ModelTypeSet& types);
   void SetActiveDataTypes(const ModelTypeSet& types);
+  void SetBackedOffDataTypes(const ModelTypeSet& types);
   void SetLastCycleSnapshot(const SyncCycleSnapshot& snapshot);
   void SetUserDemographics(
       const UserDemographicsResult& user_demographics_result);
@@ -74,6 +75,7 @@
   ModelTypeSet GetRegisteredDataTypes() const override;
   ModelTypeSet GetPreferredDataTypes() const override;
   ModelTypeSet GetActiveDataTypes() const override;
+  ModelTypeSet GetBackedOffDataTypes() const override;
 
   void StopAndClear() override;
   void OnDataTypeRequestsSyncStartup(ModelType type) override;
@@ -126,6 +128,7 @@
 
   ModelTypeSet preferred_data_types_;
   ModelTypeSet active_data_types_;
+  ModelTypeSet backed_off_data_types_;
 
   bool detailed_sync_status_engine_available_ = false;
   SyncStatus detailed_sync_status_;
diff --git a/components/sync/engine/fake_sync_engine.cc b/components/sync/engine/fake_sync_engine.cc
index 69366d02..0c95f6e 100644
--- a/components/sync/engine/fake_sync_engine.cc
+++ b/components/sync/engine/fake_sync_engine.cc
@@ -72,8 +72,8 @@
   return nullptr;
 }
 
-SyncStatus FakeSyncEngine::GetDetailedStatus() {
-  return SyncStatus();
+const SyncStatus& FakeSyncEngine::GetDetailedStatus() const {
+  return default_sync_status_;
 }
 
 void FakeSyncEngine::HasUnsyncedItemsForTest(
diff --git a/components/sync/engine/fake_sync_engine.h b/components/sync/engine/fake_sync_engine.h
index 3b35461..b38487f 100644
--- a/components/sync/engine/fake_sync_engine.h
+++ b/components/sync/engine/fake_sync_engine.h
@@ -70,7 +70,7 @@
 
   UserShare* GetUserShare() const override;
 
-  SyncStatus GetDetailedStatus() override;
+  const SyncStatus& GetDetailedStatus() const override;
 
   void HasUnsyncedItemsForTest(
       base::OnceCallback<void(bool)> cb) const override;
@@ -95,6 +95,7 @@
  private:
   bool fail_initial_download_ = false;
   bool initialized_ = false;
+  const SyncStatus default_sync_status_;
 };
 
 }  // namespace syncer
diff --git a/components/sync/engine/mock_sync_engine.h b/components/sync/engine/mock_sync_engine.h
index 0dbf894..764401d 100644
--- a/components/sync/engine/mock_sync_engine.h
+++ b/components/sync/engine/mock_sync_engine.h
@@ -49,7 +49,7 @@
   MOCK_METHOD1(Shutdown, void(ShutdownReason));
   MOCK_METHOD0(EnableEncryptEverything, void());
   MOCK_CONST_METHOD0(GetUserShare, UserShare*());
-  MOCK_METHOD0(GetDetailedStatus, SyncStatus());
+  MOCK_CONST_METHOD0(GetDetailedStatus, const SyncStatus&());
   MOCK_CONST_METHOD1(HasUnsyncedItemsForTest,
                      void(base::OnceCallback<void(bool)>));
   MOCK_CONST_METHOD1(GetModelSafeRoutingInfo, void(ModelSafeRoutingInfo*));
diff --git a/components/sync/engine/sync_engine.h b/components/sync/engine/sync_engine.h
index 3f9c99bd..322cbdaa 100644
--- a/components/sync/engine/sync_engine.h
+++ b/components/sync/engine/sync_engine.h
@@ -156,8 +156,8 @@
   // OnBackendInitialized().
   virtual UserShare* GetUserShare() const = 0;
 
-  // Called from any thread to obtain current detailed status information.
-  virtual SyncStatus GetDetailedStatus() = 0;
+  // Returns current detailed status information.
+  virtual const SyncStatus& GetDetailedStatus() const = 0;
 
   // Determines if the underlying sync engine has made any local changes to
   // items that have not yet been synced with the server.
diff --git a/components/sync/engine/sync_engine_host.h b/components/sync/engine/sync_engine_host.h
index 487d449..f1ef8b7e 100644
--- a/components/sync/engine/sync_engine_host.h
+++ b/components/sync/engine/sync_engine_host.h
@@ -87,6 +87,9 @@
 
   // Called when the sync cycle returns there is an user actionable error.
   virtual void OnActionableError(const SyncProtocolError& error) = 0;
+
+  // Called when the set of backed off types is changed.
+  virtual void OnBackedOffTypesChanged() = 0;
 };
 
 }  // namespace syncer
diff --git a/components/sync/engine/sync_engine_host_stub.cc b/components/sync/engine/sync_engine_host_stub.cc
index d9362eb..a4e7e4a4e 100644
--- a/components/sync/engine/sync_engine_host_stub.cc
+++ b/components/sync/engine/sync_engine_host_stub.cc
@@ -40,4 +40,6 @@
 
 void SyncEngineHostStub::OnActionableError(const SyncProtocolError& error) {}
 
+void SyncEngineHostStub::OnBackedOffTypesChanged() {}
+
 }  // namespace syncer
diff --git a/components/sync/engine/sync_engine_host_stub.h b/components/sync/engine/sync_engine_host_stub.h
index 5cfcfd43..4dde90d5 100644
--- a/components/sync/engine/sync_engine_host_stub.h
+++ b/components/sync/engine/sync_engine_host_stub.h
@@ -37,6 +37,7 @@
   void OnConnectionStatusChange(ConnectionStatus status) override;
   void OnMigrationNeededForTypes(ModelTypeSet types) override;
   void OnActionableError(const SyncProtocolError& error) override;
+  void OnBackedOffTypesChanged() override;
 };
 
 }  // namespace syncer
diff --git a/components/sync/nigori/nigori_state.cc b/components/sync/nigori/nigori_state.cc
index c05a96db..798b7b5 100644
--- a/components/sync/nigori/nigori_state.cc
+++ b/components/sync/nigori/nigori_state.cc
@@ -273,8 +273,6 @@
     specifics.set_custom_passphrase_time(
         TimeToProtoTime(custom_passphrase_time));
   }
-  // TODO(crbug.com/922900): add other fields support.
-  NOTIMPLEMENTED();
   return specifics;
 }
 
diff --git a/components/sync_bookmarks/bookmark_model_type_processor.cc b/components/sync_bookmarks/bookmark_model_type_processor.cc
index 3c420c4..8ae9986 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor.cc
+++ b/components/sync_bookmarks/bookmark_model_type_processor.cc
@@ -447,6 +447,8 @@
     syncer::UpdateResponseDataList updates) {
   DCHECK(!bookmark_tracker_);
 
+  TRACE_EVENT0("sync", "BookmarkModelTypeProcessor::OnInitialUpdateReceived");
+
   bookmark_tracker_ = SyncedBookmarkTracker::CreateEmpty(model_type_state);
   StartTrackingMetadata();
 
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler.cc b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
index 30a5490..5ccdcae 100644
--- a/components/sync_bookmarks/bookmark_remote_updates_handler.cc
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
@@ -15,6 +15,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_piece.h"
+#include "base/trace_event/trace_event.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_node.h"
 #include "components/sync/base/unique_position.h"
@@ -96,6 +97,9 @@
 size_t ComputeChildNodeIndex(const bookmarks::BookmarkNode* parent,
                              const sync_pb::UniquePosition& unique_position,
                              const SyncedBookmarkTracker* bookmark_tracker) {
+  // TODO(crbug.com/1084150): remove after investigations are completed.
+  TRACE_EVENT0("sync", "ComputeChildNodeIndex");
+
   const syncer::UniquePosition position =
       syncer::UniquePosition::FromProto(unique_position);
   for (size_t i = 0; i < parent->children().size(); ++i) {
@@ -191,6 +195,8 @@
 void BookmarkRemoteUpdatesHandler::Process(
     const syncer::UpdateResponseDataList& updates,
     bool got_new_encryption_requirements) {
+  TRACE_EVENT0("sync", "BookmarkRemoteUpdatesHandler::Process");
+
   bookmark_tracker_->CheckAllNodesTracked(bookmark_model_);
   // If new encryption requirements come from the server, the entities that are
   // in |updates| will be recorded here so they can be ignored during the
diff --git a/components/sync_bookmarks/synced_bookmark_tracker.h b/components/sync_bookmarks/synced_bookmark_tracker.h
index ffc8678..0de4063 100644
--- a/components/sync_bookmarks/synced_bookmark_tracker.h
+++ b/components/sync_bookmarks/synced_bookmark_tracker.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <unordered_map>
 #include <utility>
 #include <vector>
 
@@ -342,7 +343,7 @@
   // A map of bookmark nodes to sync entities. It's keyed by the bookmark node
   // pointers which get assigned when loading the bookmark model. This map is
   // first initialized in the constructor.
-  std::map<const bookmarks::BookmarkNode*, Entity*>
+  std::unordered_map<const bookmarks::BookmarkNode*, Entity*>
       bookmark_node_to_entities_map_;
 
   // A list of pending local bookmark deletions. They should be sent to the
diff --git a/components/test/data/autofill_assistant/html/autofill_assistant_target_website.html b/components/test/data/autofill_assistant/html/autofill_assistant_target_website.html
index 5dc8bac..2221c7b 100644
--- a/components/test/data/autofill_assistant/html/autofill_assistant_target_website.html
+++ b/components/test/data/autofill_assistant/html/autofill_assistant_target_website.html
@@ -262,6 +262,15 @@
       <a href="#">I have read and understood <br />the terms and conditions</a>
     </label>
 
+    <label id="option1_label" for="option1">Option <b>1</b></label>
+    <input type="checkbox" id="option1">
+    <label id="option2_label">
+      Option <b>2</b>
+      <input id="option2" type="checkbox" name="option2">
+    </label>
+    <label id="bad_label1" for="doesnotexist">A label without an element</label>
+    <label id="bad_label2">Another label without an element</label>
+    
     <script>
       let upperCaseInput = document.querySelector("#uppercase_input");
       document.addEventListener('keyup', () => {
@@ -313,5 +322,8 @@
       <div id="scroll_item_5" style="width:50px;height:50px">5</div>
     </div>
     <div id="after_scroll_container"/>
+
+    <div>Section with text only</div>
+    <div>Section with text and <button onclick="removeButton()">some button</button></div>
   </body>
 </html>
diff --git a/components/test/data/autofill_assistant/html/autofill_assistant_target_website_iframe_two.html b/components/test/data/autofill_assistant/html/autofill_assistant_target_website_iframe_two.html
index 5c25760..b2368d8f 100644
--- a/components/test/data/autofill_assistant/html/autofill_assistant_target_website_iframe_two.html
+++ b/components/test/data/autofill_assistant/html/autofill_assistant_target_website_iframe_two.html
@@ -41,4 +41,4 @@
       <button id="button" type="button">Test Button</button><br>
     </div>
   </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/components/test/data/payments/maxpay.com/app.json b/components/test/data/payments/maxpay.com/app.json
deleted file mode 100644
index fcf8e26..0000000
--- a/components/test/data/payments/maxpay.com/app.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "name": "Max Pay",
-  "icons": [{
-    "src": "../icon.png",
-    "sizes": "40x40",
-    "type": "image/png"
-  }],
-  "serviceworker": {
-    "src": "payment_handler_sw.js"
-  }
-}
diff --git a/components/test/data/payments/maxpay.com/installer.js b/components/test/data/payments/maxpay.com/installer.js
index 6b06b95e..10fa4e0 100644
--- a/components/test/data/payments/maxpay.com/installer.js
+++ b/components/test/data/payments/maxpay.com/installer.js
@@ -4,8 +4,7 @@
  * found in the LICENSE file.
  */
 
-const methodName = window.location.origin +
-    '/components/test/data/payments/maxpay.com/payment_method.json';
+const methodName = window.location.origin + '/pay';
 const swSrcUrl = './payment_handler_sw.js';
 let resultPromise;
 
diff --git a/components/test/data/payments/maxpay.com/merchant.html b/components/test/data/payments/maxpay.com/merchant.html
index 03d6efe..59691f10 100644
--- a/components/test/data/payments/maxpay.com/merchant.html
+++ b/components/test/data/payments/maxpay.com/merchant.html
@@ -47,9 +47,9 @@
     </script>
     <h1>Use Max Pay</h1>
     <div id="controllers">
-      <button id="install" onclick="onInstallClicked()">Install</button>
-      <button id="uninstall" onclick="onUninstallClicked()">Uninstall</button>
-      <button id="launch" onclick="onLaunchClicked()">Launch</button>
+      <button onclick="onInstallClicked()">Install</button>
+      <button onclick="onUninstallClicked()">Uninstall</button>
+      <button onclick="onLaunchClicked()">Launch</button>
       <button onclick="onLaunchClicked('http://info.cern.ch')">Launch http app</button>
     </div>
     <div>
diff --git a/components/test/data/payments/maxpay.com/payment_handler_window.html b/components/test/data/payments/maxpay.com/payment_handler_window.html
index 050c3bb..fb7e5034 100644
--- a/components/test/data/payments/maxpay.com/payment_handler_window.html
+++ b/components/test/data/payments/maxpay.com/payment_handler_window.html
@@ -4,13 +4,9 @@
 Use of this source code is governed by a BSD-style license that can be
 found in the LICENSE file.
 -->
-<head>
-  <meta charset="utf-8">
-  <meta
-    name="viewport"
-    content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
-  <title>Max Pay</title>
-</head>
+<meta
+  name="viewport"
+  content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
 <body>
   <button onclick="confirm()">confirm</button>
   <button onclick="cancel()">cancel</button>
diff --git a/components/test/data/payments/maxpay.com/payment_method.json b/components/test/data/payments/maxpay.com/payment_method.json
deleted file mode 100644
index b320f39..0000000
--- a/components/test/data/payments/maxpay.com/payment_method.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "default_applications": ["app.json"]
-}
diff --git a/components/translate/core/browser/translate_infobar_delegate.cc b/components/translate/core/browser/translate_infobar_delegate.cc
index 0a01fde8..1404f70 100644
--- a/components/translate/core/browser/translate_infobar_delegate.cc
+++ b/components/translate/core/browser/translate_infobar_delegate.cc
@@ -148,6 +148,10 @@
   return language_name_at(ui_delegate_.GetOriginalLanguageIndex());
 }
 
+base::string16 TranslateInfoBarDelegate::target_language_name() const {
+  return language_name_at(ui_delegate_.GetTargetLanguageIndex());
+}
+
 void TranslateInfoBarDelegate::UpdateOriginalLanguage(
     const std::string& language_code) {
   ui_delegate_.UpdateOriginalLanguage(language_code);
diff --git a/components/translate/core/browser/translate_infobar_delegate.h b/components/translate/core/browser/translate_infobar_delegate.h
index d6a30702..2a8eeee 100644
--- a/components/translate/core/browser/translate_infobar_delegate.h
+++ b/components/translate/core/browser/translate_infobar_delegate.h
@@ -117,9 +117,7 @@
     return ui_delegate_.GetTargetLanguageCode();
   }
 
-  base::string16 target_language_name() const {
-    return language_name_at(ui_delegate_.GetTargetLanguageIndex());
-  }
+  virtual base::string16 target_language_name() const;
 
   virtual void UpdateTargetLanguage(const std::string& language_code);
 
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc
index 8bce38a..6d26c63 100644
--- a/components/viz/service/display/surface_aggregator.cc
+++ b/components/viz/service/display/surface_aggregator.cc
@@ -118,9 +118,39 @@
   bool is_fast_rounded_corner;
 };
 
+struct SurfaceAggregator::ChildSurfaceInfo {
+  struct QuadStateInfo {
+    gfx::Transform transform_to_root_target;
+    gfx::Transform quad_to_target_transform;
+    gfx::Rect clip_rect;
+    bool is_clipped;
+  };
+
+  ChildSurfaceInfo(RenderPassId parent_pass_id,
+                   const gfx::Rect& quad_rect,
+                   bool stretch_content_to_fill_bounds)
+      : parent_pass_id(parent_pass_id),
+        quad_rect(quad_rect),
+        stretch_content_to_fill_bounds(stretch_content_to_fill_bounds) {
+    // In most cases there would be one or two different embeddings of a
+    // surface in the render pass tree. Reserve two elements to avoid
+    // unnecessary copies.
+    quad_state_infos.reserve(2);
+  }
+
+  RenderPassId parent_pass_id;
+  gfx::Rect quad_rect;
+  bool stretch_content_to_fill_bounds;
+  bool has_moved_pixels = false;
+  std::vector<QuadStateInfo> quad_state_infos;
+};
+
 struct SurfaceAggregator::RenderPassMapEntry {
-  explicit RenderPassMapEntry(RenderPass* render_pass)
-      : render_pass(render_pass) {}
+  RenderPassMapEntry(RenderPass* render_pass,
+                     bool has_pixel_moving_backdrop_filter)
+      : render_pass(render_pass),
+        damage_rect(render_pass->output_rect),
+        has_pixel_moving_backdrop_filter(has_pixel_moving_backdrop_filter) {}
 
   // Make this move-only.
   RenderPassMapEntry(RenderPassMapEntry&&) = default;
@@ -131,8 +161,12 @@
   RenderPass* render_pass;
   // Damage rect of the render pass in its own content space.
   gfx::Rect damage_rect;
+  bool has_pixel_moving_backdrop_filter;
 
   bool is_visited = false;
+  // If the render pass contains any surfaces in its quad list, either from
+  // SurfaceDrawQuads or from render passes referenced by RPDQs.
+  bool contains_surfaces = false;
 };
 
 SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager,
@@ -164,16 +198,18 @@
   // This data is created once and typically small or empty. Collect all items
   // and pass to a flat_map to sort once.
   std::vector<std::pair<RenderPassId, RenderPassMapEntry>> render_pass_data;
-  render_pass_data.reserve(render_pass_list.size());
   for (const auto& render_pass : render_pass_list) {
-    if (render_pass->backdrop_filters.HasFilterThatMovesPixels()) {
+    bool has_pixel_moving_backdrop_filter =
+        render_pass->backdrop_filters.HasFilterThatMovesPixels();
+    if (has_pixel_moving_backdrop_filter) {
       DCHECK_NE(render_pass.get(), root_pass_in_root_surface)
           << "The root render pass on the root surface can not have backdrop "
              "affecting filters";
     }
-    render_pass_data.emplace_back(std::piecewise_construct,
-                                  std::forward_as_tuple(render_pass->id),
-                                  std::forward_as_tuple(render_pass.get()));
+    render_pass_data.emplace_back(
+        std::piecewise_construct, std::forward_as_tuple(render_pass->id),
+        std::forward_as_tuple(render_pass.get(),
+                              has_pixel_moving_backdrop_filter));
   }
   return base::flat_map<RenderPassId, RenderPassMapEntry>(
       std::move(render_pass_data));
@@ -1199,52 +1235,125 @@
   }
 }
 
-gfx::Rect SurfaceAggregator::PrewalkRenderPass(
-    RenderPassId render_pass_id,
-    const Surface* surface,
+void SurfaceAggregator::FindChildSurfaces(
+    SurfaceId surface_id,
     base::flat_map<RenderPassId, RenderPassMapEntry>* render_pass_map,
-    bool will_draw,
+    RenderPassMapEntry* current_pass_entry,
     const gfx::Transform& transform_to_root_target,
+    base::flat_map<SurfaceRange, ChildSurfaceInfo>* child_surfaces,
     std::vector<gfx::Rect>* pixel_moving_backdrop_filters_rects,
-    PrewalkResult* result) {
-  auto it = render_pass_map->find(render_pass_id);
-  DCHECK(it != render_pass_map->end());
-  RenderPassMapEntry& render_pass_entry = it->second;
-  if (render_pass_entry.is_visited) {
-    // This render pass is an ancestor of itself (not supported) or has been
-    // processed.
-    return render_pass_entry.damage_rect;
+    bool* has_backdrop_cache_flags_to_update) {
+  if (current_pass_entry->is_visited) {
+    // This means that this render pass is an ancestor of itself. This is not
+    // supported. Stop processing the render pass again.
+    return;
   }
-  render_pass_entry.is_visited = true;
-  const RenderPass& render_pass = *render_pass_entry.render_pass;
-
-  if (render_pass.backdrop_filters.HasFilterThatMovesPixels()) {
+  base::AutoReset<bool> reset_is_visited(&current_pass_entry->is_visited, true);
+  RenderPass* render_pass = current_pass_entry->render_pass;
+  if (current_pass_entry->has_pixel_moving_backdrop_filter) {
     has_pixel_moving_backdrop_filter_ = true;
     // If the render pass has a backdrop filter that moves pixels, its entire
     // bounds, with proper transform applied, may be added to the damage
     // rect if it intersects.
     pixel_moving_backdrop_filters_rects->push_back(
         cc::MathUtil::MapEnclosingClippedRect(transform_to_root_target,
-                                              render_pass.output_rect));
+                                              render_pass->output_rect));
   }
-
-  RenderPassId remapped_pass_id =
-      RemapPassId(render_pass.id, surface->surface_id());
-  // |moved_pixel_passes_| stores all the render passes affected by filters
-  // that move pixels, so |has_pixel_moving_filter| should be set to true either
-  // if the current render pass has pixel_moving_filter(s) or if it is inside an
-  // ancestor render pass that has pixel_moving_filter(s).
-  bool has_pixel_moving_filter = render_pass.filters.HasFilterThatMovesPixels();
+  RenderPassId remapped_pass_id = RemapPassId(render_pass->id, surface_id);
+  bool has_pixel_moving_filter =
+      render_pass->filters.HasFilterThatMovesPixels();
   if (has_pixel_moving_filter)
     moved_pixel_passes_.insert(remapped_pass_id);
   bool in_moved_pixel_pass =
       has_pixel_moving_filter ||
       base::Contains(moved_pixel_passes_, remapped_pass_id);
+  for (auto* quad : render_pass->quad_list) {
+    if (quad->material == DrawQuad::Material::kSurfaceContent) {
+      // A child surface has been found. Add necessary info from this surface to
+      // the set of child surfaces that can be used to update damage rect for
+      // the parent surface. If this child surface has been visited previously,
+      // we only need to update |has_moved_pixels| and add the transform
+      // corresponding to this visit; rest of the info would remain the same.
+      const auto* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
+      auto it = child_surfaces->find(surface_quad->surface_range);
+      if (it == child_surfaces->end()) {
+        auto insert_pair = child_surfaces->emplace(
+            std::piecewise_construct,
+            std::forward_as_tuple(surface_quad->surface_range),
+            std::forward_as_tuple(
+                remapped_pass_id, surface_quad->rect,
+                surface_quad->stretch_content_to_fill_bounds));
+        DCHECK(insert_pair.second);
+        it = insert_pair.first;
+      }
+      auto& child_surface_info = it->second;
+      if (in_moved_pixel_pass)
+        child_surface_info.has_moved_pixels = true;
+      child_surface_info.quad_state_infos.push_back(
+          {transform_to_root_target,
+           surface_quad->shared_quad_state->quad_to_target_transform,
+           surface_quad->shared_quad_state->clip_rect,
+           surface_quad->shared_quad_state->is_clipped});
+      current_pass_entry->contains_surfaces = true;
+    } else if (quad->material == DrawQuad::Material::kRenderPass) {
+      // A child render pass has been found. Find its child surfaces
+      // recursively.
+      const auto* render_pass_quad = RenderPassDrawQuad::MaterialCast(quad);
+      *has_backdrop_cache_flags_to_update |=
+          render_pass_quad->can_use_backdrop_filter_cache;
+      RenderPassId child_pass_id = render_pass_quad->render_pass_id;
+      RenderPassId remapped_child_pass_id =
+          RemapPassId(child_pass_id, surface_id);
+      if (in_moved_pixel_pass)
+        moved_pixel_passes_.insert(remapped_child_pass_id);
+      auto child_pass_it = render_pass_map->find(child_pass_id);
+      DCHECK(child_pass_it != render_pass_map->end());
+      RenderPassMapEntry& child_pass_entry = child_pass_it->second;
+      // TODO(crbug/1011042): Here, we used to set |in_moved_pixel_pass| to true
+      // if the child render pass has a pixel-moving backdrop filter. This
+      // behavior was added in r687426 to fix another problem, but caused a huge
+      // performance issue in some cases that enabled background blur, by
+      // expanding the damage rect unnecessarily to the entire screen
+      // (crbug/1008740). This is removed now, but a proper fix for the
+      // pixel-moving backdrop filter should be implemented.
+      render_pass_dependencies_[remapped_pass_id].insert(
+          remapped_child_pass_id);
+      FindChildSurfaces(
+          surface_id, render_pass_map, &child_pass_entry,
+          gfx::Transform(
+              transform_to_root_target,
+              render_pass_quad->shared_quad_state->quad_to_target_transform),
+          child_surfaces, pixel_moving_backdrop_filters_rects,
+          has_backdrop_cache_flags_to_update);
+      current_pass_entry->contains_surfaces |=
+          child_pass_entry.contains_surfaces;
+    }
+  }
+}
 
-  const CompositorFrame& frame = surface->GetActiveFrame();
-  gfx::Rect full_damage = frame.render_pass_list.back()->output_rect;
+gfx::Rect
+SurfaceAggregator::UpdateRPDQCanUseBackdropFilterCacheWithSurfaceDamage(
+    RenderPassId id,
+    PrewalkResult* result,
+    base::flat_map<RenderPassId, RenderPassMapEntry>* render_pass_map) {
+  auto render_pass_it = render_pass_map->find(id);
+  DCHECK(render_pass_it != render_pass_map->end());
+  RenderPassMapEntry& render_pass_entry = render_pass_it->second;
 
+  // If there's no surface embedded in the render pass, return an empty rect.
+  if (!render_pass_entry.contains_surfaces)
+    return gfx::Rect();
+
+  if (render_pass_entry.is_visited) {
+    // This render pass is an ancestor of itself (not supported) or has been
+    // processed.
+    return render_pass_entry.damage_rect;
+  }
+  render_pass_entry.is_visited = true;
+
+  const RenderPass& render_pass = *render_pass_entry.render_pass;
   gfx::Rect damage_rect;
+
   // Iterate through the quad list back-to-front and accumulate damage from
   // all quads (only SurfaceDrawQuads and RenderPassDrawQuads can have damage
   // at this point). |damage_rect| has damage from all quads below the current
@@ -1253,50 +1362,36 @@
   for (QuadList::ConstReverseIterator it = render_pass.quad_list.rbegin();
        it != render_pass.quad_list.rend(); ++it) {
     const DrawQuad* quad = *it;
-    gfx::Rect quad_damage_rect;
     if (quad->material == DrawQuad::Material::kSurfaceContent) {
       const auto* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
-      Surface* child_surface =
+      Surface* surface =
           manager_->GetLatestInFlightSurface(surface_quad->surface_range);
-      // If the primary surface is not available then we assume the damage is
-      // the full size of the SurfaceDrawQuad because we might need to introduce
-      // gutter.
-      if (!child_surface ||
-          child_surface->surface_id() != surface_quad->surface_range.end()) {
-        quad_damage_rect = quad->rect;
-      }
-
-      if (child_surface) {
-        gfx::Rect child_rect;
-        auto it = result->damage_on_surfaces.find(child_surface->surface_id());
-        if (it != result->damage_on_surfaces.end()) {
-          // the surface damage has been accummulated previously
-          child_rect = it->second;
-        } else {
-          // first encounter of the surface
-          child_rect = PrewalkSurface(child_surface, in_moved_pixel_pass,
-                                      remapped_pass_id, will_draw, result);
-        }
-
+      auto it = result->damage_on_surfaces.end();
+      if (surface)
+        it = result->damage_on_surfaces.find(surface->surface_id());
+      if (it != result->damage_on_surfaces.end()) {
+        gfx::Rect surface_damage_rect = it->second;
         if (surface_quad->stretch_content_to_fill_bounds) {
-          if (!child_surface->size_in_pixels().IsEmpty()) {
+          if (surface->size_in_pixels().GetCheckedArea().ValueOrDefault(0) >
+              0) {
             float y_scale = static_cast<float>(surface_quad->rect.height()) /
-                            child_surface->size_in_pixels().height();
+                            surface->size_in_pixels().height();
             float x_scale = static_cast<float>(surface_quad->rect.width()) /
-                            child_surface->size_in_pixels().width();
-            child_rect =
-                gfx::ScaleToEnclosingRect(child_rect, x_scale, y_scale);
+                            surface->size_in_pixels().width();
+            surface_damage_rect = gfx::ScaleToEnclosingRect(surface_damage_rect,
+                                                            x_scale, y_scale);
           }
         }
-        quad_damage_rect.Union(child_rect);
-      }
-
-      if (quad_damage_rect.IsEmpty())
-        continue;
-
-      if (in_moved_pixel_pass) {
-        damage_rect = full_damage;
-        continue;
+        gfx::Rect rect_in_target_space = cc::MathUtil::MapEnclosingClippedRect(
+            quad->shared_quad_state->quad_to_target_transform,
+            surface_damage_rect);
+        damage_rect.Union(rect_in_target_space);
+      } else {
+        // The damage info was not found for the (probably invalid) surface,
+        // take the whole quad rect as damaged.
+        gfx::Rect rect_in_target_space = cc::MathUtil::MapEnclosingClippedRect(
+            quad->shared_quad_state->quad_to_target_transform, quad->rect);
+        damage_rect.Union(rect_in_target_space);
       }
     } else if (quad->material == DrawQuad::Material::kRenderPass) {
       auto* render_pass_quad = RenderPassDrawQuad::MaterialCast(quad);
@@ -1311,42 +1406,28 @@
           render_pass_quad->can_use_backdrop_filter_cache = false;
       }
 
-      RenderPassId child_pass_id = render_pass_quad->render_pass_id;
-      RenderPassId remapped_child_pass_id =
-          RemapPassId(child_pass_id, surface->surface_id());
-      if (in_moved_pixel_pass)
-        moved_pixel_passes_.insert(remapped_child_pass_id);
+      gfx::Rect render_pass_damage_rect =
+          UpdateRPDQCanUseBackdropFilterCacheWithSurfaceDamage(
+              render_pass_quad->render_pass_id, result, render_pass_map);
 
-      render_pass_dependencies_[remapped_pass_id].insert(
-          remapped_child_pass_id);
-      quad_damage_rect = PrewalkRenderPass(
-          child_pass_id, surface, render_pass_map, will_draw,
-          gfx::Transform(
-              transform_to_root_target,
-              render_pass_quad->shared_quad_state->quad_to_target_transform),
-          pixel_moving_backdrop_filters_rects, result);
-
-    } else {
-      continue;
+      gfx::Rect rect = cc::MathUtil::MapEnclosingClippedRect(
+          render_pass_quad->shared_quad_state->quad_to_target_transform,
+          render_pass_damage_rect);
+      damage_rect.Union(rect);
     }
-    // Convert the quad damage rect into its target space and clip it
-    // if needed.
-    gfx::Rect rect_in_target_space = cc::MathUtil::MapEnclosingClippedRect(
-        quad->shared_quad_state->quad_to_target_transform, quad_damage_rect);
-    if (quad->shared_quad_state->is_clipped) {
-      rect_in_target_space.Intersect(quad->shared_quad_state->clip_rect);
-    }
-    damage_rect.Union(rect_in_target_space);
   }
   render_pass_entry.damage_rect = damage_rect;
   return damage_rect;
 }
 
-gfx::Rect SurfaceAggregator::PrewalkSurface(Surface* surface,
-                                            bool in_moved_pixel_surface,
-                                            int parent_pass_id,
-                                            bool will_draw,
-                                            PrewalkResult* result) {
+// Walk the Surface tree from surface_id. Validate the resources of the current
+// surface and its descendants, check if there are any copy requests, and
+// return the combined damage rect.
+gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
+                                         bool in_moved_pixel_surface,
+                                         int parent_pass_id,
+                                         bool will_draw,
+                                         PrewalkResult* result) {
   if (referenced_surfaces_.count(surface->surface_id()))
     return gfx::Rect();
 
@@ -1389,6 +1470,17 @@
   base::flat_map<RenderPassId, RenderPassMapEntry> render_pass_map =
       GenerateRenderPassMap(frame.render_pass_list, IsRootSurface(surface));
 
+  auto root_pass_it = render_pass_map.find(frame.render_pass_list.back()->id);
+  DCHECK(root_pass_it != render_pass_map.end());
+  RenderPassMapEntry& root_pass_entry = root_pass_it->second;
+  base::flat_map<SurfaceRange, ChildSurfaceInfo> child_surfaces;
+  std::vector<gfx::Rect> pixel_moving_backdrop_filters_rects;
+  bool has_backdrop_cache_flags_to_update = false;
+  FindChildSurfaces(surface->surface_id(), &render_pass_map, &root_pass_entry,
+                    root_pass_transform, &child_surfaces,
+                    &pixel_moving_backdrop_filters_rects,
+                    &has_backdrop_cache_flags_to_update);
+
   std::vector<ResourceId> referenced_resources;
   referenced_resources.reserve(frame.resource_list.size());
 
@@ -1426,10 +1518,82 @@
   // Avoid infinite recursion by adding current surface to
   // |referenced_surfaces_|.
   referenced_surfaces_.insert(surface->surface_id());
-  std::vector<gfx::Rect> pixel_moving_backdrop_filters_rects;
-  damage_rect.Union(PrewalkRenderPass(
-      frame.render_pass_list.back()->id, surface, &render_pass_map, will_draw,
-      root_pass_transform, &pixel_moving_backdrop_filters_rects, result));
+  for (const auto& child_surface_info_pair : child_surfaces) {
+    auto& child_surface_range = child_surface_info_pair.first;
+    auto& child_surface_info = child_surface_info_pair.second;
+    // TODO(fsamuel): Consider caching this value somewhere so that
+    // HandleSurfaceQuad doesn't need to call it again.
+    Surface* child_surface =
+        manager_->GetLatestInFlightSurface(child_surface_range);
+
+    // If the primary surface is not available then we assume the damage is
+    // the full size of the SurfaceDrawQuad because we might need to introduce
+    // gutter.
+    gfx::Rect child_surface_damage;
+    if (!child_surface ||
+        child_surface->surface_id() != child_surface_range.end()) {
+      child_surface_damage = child_surface_info.quad_rect;
+    }
+
+    if (child_surface) {
+      if (child_surface_info.stretch_content_to_fill_bounds) {
+        // Scale up the damage_quad generated by the child_surface to fit
+        // the containing quad_rect.
+        gfx::Rect child_rect =
+            PrewalkTree(child_surface, child_surface_info.has_moved_pixels,
+                        child_surface_info.parent_pass_id, will_draw, result);
+        if (child_surface->size_in_pixels().GetCheckedArea().ValueOrDefault(0) >
+            0) {
+          float y_scale =
+              static_cast<float>(child_surface_info.quad_rect.height()) /
+              child_surface->size_in_pixels().height();
+          float x_scale =
+              static_cast<float>(child_surface_info.quad_rect.width()) /
+              child_surface->size_in_pixels().width();
+          child_surface_damage.Union(
+              gfx::ScaleToEnclosingRect(child_rect, x_scale, y_scale));
+        }
+      } else {
+        child_surface_damage.Union(
+            PrewalkTree(child_surface, child_surface_info.has_moved_pixels,
+                        child_surface_info.parent_pass_id, will_draw, result));
+      }
+    }
+
+    if (child_surface_damage.IsEmpty())
+      continue;
+
+    if (child_surface_info.has_moved_pixels) {
+      // Areas outside the rect hit by target_to_surface_transform may be
+      // modified if there is a filter that moves pixels.
+      damage_rect = full_damage;
+      continue;
+    }
+
+    // Add the child surface damage rect to the parent surface damage rect. The
+    // child surface damage rect is first transformed to the parent surface
+    // coordinate space. There would be multiple transforms for a child surface
+    // if it is embedded multiple times which means its damage rect should be
+    // added multiple times.
+    for (const auto& quad_state_info : child_surface_info.quad_state_infos) {
+      gfx::Transform target_to_surface_transform(
+          quad_state_info.transform_to_root_target,
+          quad_state_info.quad_to_target_transform);
+
+      gfx::Rect child_surface_damage_in_root_target_space =
+          cc::MathUtil::MapEnclosingClippedRect(target_to_surface_transform,
+                                                child_surface_damage);
+      if (quad_state_info.is_clipped) {
+        gfx::Rect clip_rect_in_root_target_space =
+            cc::MathUtil::MapEnclosingClippedRect(
+                quad_state_info.transform_to_root_target,
+                quad_state_info.clip_rect);
+        child_surface_damage_in_root_target_space.Intersect(
+            clip_rect_in_root_target_space);
+      }
+      damage_rect.Union(child_surface_damage_in_root_target_space);
+    }
+  }
 
   if (!damage_rect.IsEmpty()) {
     // The following call can cause one or more copy requests to be added to the
@@ -1471,7 +1635,7 @@
       result->undrawn_surfaces.insert(surface_id);
       Surface* undrawn_surface = manager_->GetSurfaceForId(surface_id);
       if (undrawn_surface)
-        PrewalkSurface(undrawn_surface, false, 0, /*will_draw=*/false, result);
+        PrewalkTree(undrawn_surface, false, 0, false /* will_draw */, result);
     }
   }
 
@@ -1509,6 +1673,11 @@
       std::forward_as_tuple(damage_rect));
   DCHECK(emplace_result.second);
 
+  if (has_backdrop_cache_flags_to_update) {
+    UpdateRPDQCanUseBackdropFilterCacheWithSurfaceDamage(
+        frame.render_pass_list.back()->id, result, &render_pass_map);
+  }
+
   return damage_rect;
 }
 
@@ -1643,13 +1812,12 @@
   DCHECK(referenced_surfaces_.empty());
   PrewalkResult prewalk_result;
   gfx::Rect surfaces_damage_rect =
-      PrewalkSurface(surface, false, 0, /*will_draw=*/true, &prewalk_result);
+      PrewalkTree(surface, false, 0, true /* will_draw */, &prewalk_result);
 
   root_damage_rect_ = surfaces_damage_rect;
   // |root_damage_rect_| is used to restrict aggregating quads only if they
   // intersect this area.
   root_damage_rect_.Union(target_damage);
-
   root_content_color_usage_ = prewalk_result.content_color_usage;
 
   if (prewalk_result.frame_sinks_changed)
diff --git a/components/viz/service/display/surface_aggregator.h b/components/viz/service/display/surface_aggregator.h
index b8127141..bdc4db4 100644
--- a/components/viz/service/display/surface_aggregator.h
+++ b/components/viz/service/display/surface_aggregator.h
@@ -186,42 +186,61 @@
       const gfx::Rect& occluding_damage_rect,
       bool occluding_damage_rect_valid);
 
-  // Recursively walks through the render pass and updates the
-  // |can_use_backdrop_filter_cache| flag on all RenderPassDrawQuads(RPDQ).
-  // The function returns the damage rect of the render pass in its own content
-  // space.
-  //  - |render_pass_id| specifies the id of the render pass.
-  //  - |surface| is the surface containing the render pass.
-  //  - |render_pass_map| is a map that contains all render passes and their
-  //    entry data.
-  //  - |will_draw| indicates that the surface can be aggregated into the final
-  //    frame and might be drawn (based on damage/occlusion/etc.) if it is set
-  //    to true. Or the surface isn't in the aggregated frame and is only
-  //    needed for CopyOutputRequests if set to false.
+  // Helper function that uses backtracking on the render pass tree of a surface
+  // to find all surfaces embedded in it. If a surface is embedded multiple
+  // times (due to use of a MirrorLayer), it will be reachable via multiple
+  // paths from the root render pass. For each such a path the appropriate
+  // transform is calculated.
+  //  - |surface_id| specifies the surface to find all child surfaces of.
+  //  - |render_pass_map| is a pre-computed map from render pass id to some info
+  //    about the render pass, including the render pass itself and whether it
+  //    has pixel moving backdrop filter.
+  //  - |current_pass_entry| is the info about the current render pass to
+  //    process.
   //  - |transform_to_root_target| is the accumulated transform of all render
-  //    passes in the containing surface along the way to the current render
-  //    pass.
-  //  - |pixel_moving_backdrop_filters_rects| is a vector of bounds of render
-  //    passes that have a pixel moving backdrop filter.
-  //  - |result| is the result of a prewalk of the surface that contains the
-  //    render pass.
-  gfx::Rect PrewalkRenderPass(
-      RenderPassId render_pass_id,
-      const Surface* surface,
+  //    passes along the way to the current render pass.
+  //  - |child_surfaces| is the main output of the function containing all child
+  //    surfaces found in the process.
+  //  - |pixel_moving_backdrop_filters_rect| is another output that is union of
+  //    bounds of render passes that have a pixel moving backdrop filter.
+  //  - |has_backdrop_cache_flags_to_update| indicates if any
+  //    RenderPassDrawQuad(s) contained in the surface have
+  //    |can_use_backdrop_filter_cache| flag set to true and having to be
+  //    updated. This is used to avoid iterating through all the render passes
+  //    in the surface frame when not needed (i.e. no flag needs to be
+  //    updated).
+  // TODO(mohsen): Consider refactoring this backtracking algorithm into a
+  // self-contained class.
+  void FindChildSurfaces(
+      SurfaceId surface_id,
       base::flat_map<RenderPassId, RenderPassMapEntry>* render_pass_map,
-      bool will_draw,
+      RenderPassMapEntry* current_pass_entry,
       const gfx::Transform& transform_to_root_target,
+      base::flat_map<SurfaceRange, ChildSurfaceInfo>* child_surfaces,
       std::vector<gfx::Rect>* pixel_moving_backdrop_filters_rects,
-      PrewalkResult* result);
+      bool* has_backdrop_cache_flags_to_update);
 
-  // Walk the Surface tree from |surface|. Validate the resources of the
-  // current surface and its descendants, check if there are any copy requests,
-  // and return the combined damage rect.
-  gfx::Rect PrewalkSurface(Surface* surface,
-                           bool in_moved_pixel_surface,
-                           int parent_pass,
-                           bool will_draw,
-                           PrewalkResult* result);
+  // Recursively updates the |can_use_backdrop_filter_cache| flag on all
+  // RenderPassDrawQuads(RPDQ) in the specified render pass. The function
+  // recursively traverses any render pass referenced by a RPDQ but doesn't
+  // traverse any render passes in the frame of any embedded surfaces. The
+  // function returns the damage rect of the render pass in its own content
+  // space.
+  // - |id| specifies the render pass whose quads are to be updated
+  // - |result| is the result of a prewalk of a root surface that contains the
+  //   render pass
+  // - |render_pass_map| is a map that contains all render passes and their
+  // entry data
+  gfx::Rect UpdateRPDQCanUseBackdropFilterCacheWithSurfaceDamage(
+      RenderPassId id,
+      PrewalkResult* result,
+      base::flat_map<RenderPassId, RenderPassMapEntry>* render_pass_map);
+
+  gfx::Rect PrewalkTree(Surface* surface,
+                        bool in_moved_pixel_surface,
+                        int parent_pass,
+                        bool will_draw,
+                        PrewalkResult* result);
   void CopyUndrawnSurfaces(PrewalkResult* prewalk);
   void CopyPasses(const CompositorFrame& frame, Surface* surface);
   void AddColorConversionPass();
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 91e33f8..54e373e 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -2702,6 +2702,8 @@
     sources += [
       "net/cross_origin_embedder_policy_reporter.cc",
       "net/cross_origin_embedder_policy_reporter.h",
+      "net/cross_origin_opener_policy_reporter.cc",
+      "net/cross_origin_opener_policy_reporter.h",
       "net/reporting_service_proxy.cc",
       "net/reporting_service_proxy.h",
     ]
diff --git a/content/browser/accessibility/accessibility_tree_formatter_mac.mm b/content/browser/accessibility/accessibility_tree_formatter_mac.mm
index f394ba7..8b2e467 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_mac.mm
+++ b/content/browser/accessibility/accessibility_tree_formatter_mac.mm
@@ -118,8 +118,10 @@
   base::Value PopulateSize(const BrowserAccessibilityCocoa*) const;
   base::Value PopulatePosition(const BrowserAccessibilityCocoa*) const;
   base::Value PopulateRange(NSRange) const;
-  base::Value PopulateTextMarker(id,
-                                 const LineIndexesMap& line_indexes_map) const;
+  base::Value PopulateTextPosition(
+      BrowserAccessibilityPosition::AXPositionInstance::pointer,
+      const LineIndexesMap&) const;
+  base::Value PopulateTextMarkerRange(id, const LineIndexesMap&) const;
   base::Value PopulateObject(id, const LineIndexesMap& line_indexes_map) const;
   base::Value PopulateArray(NSArray*,
                             const LineIndexesMap& line_indexes_map) const;
@@ -346,10 +348,16 @@
 
   // AXTextMarker
   if (content::IsAXTextMarker(value)) {
-    return PopulateTextMarker(value, line_indexes_map);
+    return PopulateTextPosition(content::AXTextMarkerToPosition(value).get(),
+                                line_indexes_map);
   }
 
-  // Accessible object.
+  // AXTextMarkerRange
+  if (content::IsAXTextMarkerRange(value)) {
+    return PopulateTextMarkerRange(value, line_indexes_map);
+  }
+
+  // Accessible object
   if ([value isKindOfClass:[BrowserAccessibilityCocoa class]]) {
     return base::Value(NodeToLineIndex(value, line_indexes_map));
   }
@@ -367,11 +375,9 @@
   return range;
 }
 
-base::Value AccessibilityTreeFormatterMac::PopulateTextMarker(
-    id object,
+base::Value AccessibilityTreeFormatterMac::PopulateTextPosition(
+    BrowserAccessibilityPosition::AXPositionInstance::pointer position,
     const LineIndexesMap& line_indexes_map) const {
-  BrowserAccessibilityPosition::AXPositionInstance position =
-      content::AXTextMarkerToPosition(object);
   if (position->IsNullPosition()) {
     return base::Value(kNULLValue);
   }
@@ -402,6 +408,21 @@
   return set;
 }
 
+base::Value AccessibilityTreeFormatterMac::PopulateTextMarkerRange(
+    id object,
+    const LineIndexesMap& line_indexes_map) const {
+  auto range = content::AXTextMarkerRangeToRange(object);
+  if (range.IsNull()) {
+    return base::Value(kNULLValue);
+  }
+
+  base::Value dict(base::Value::Type::DICTIONARY);
+  dict.SetPath("anchor",
+               PopulateTextPosition(range.anchor(), line_indexes_map));
+  dict.SetPath("focus", PopulateTextPosition(range.focus(), line_indexes_map));
+  return dict;
+}
+
 base::Value AccessibilityTreeFormatterMac::PopulateArray(
     NSArray* node_array,
     const LineIndexesMap& line_indexes_map) const {
diff --git a/content/browser/accessibility/accessibility_tree_formatter_mac_browsertest.mm b/content/browser/accessibility/accessibility_tree_formatter_mac_browsertest.mm
index f940d0b..1c0571ed 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_mac_browsertest.mm
+++ b/content/browser/accessibility/accessibility_tree_formatter_mac_browsertest.mm
@@ -106,7 +106,8 @@
 )~~");
 }
 
-IN_PROC_BROWSER_TEST_F(AccessibilityTreeFormatterMacBrowserTest, AXTextMarker) {
+IN_PROC_BROWSER_TEST_F(AccessibilityTreeFormatterMacBrowserTest,
+                       Serialize_AXTextMarker) {
   TestAndCheck(R"~~(data:text/html,
                     <p>Paragraph</p>)~~",
                {":3;AXStartTextMarker=*"}, R"~~(AXWebArea
@@ -116,6 +117,19 @@
 }
 
 IN_PROC_BROWSER_TEST_F(AccessibilityTreeFormatterMacBrowserTest,
+                       Serialize_AXTextMarkerRange) {
+  TestAndCheck(R"~~(data:text/html,
+                    <p id='p'>Paragraph</p>
+                    <script>
+                      window.getSelection().selectAllChildren(document.getElementById('p'));
+                    </script>)~~",
+               {":3;AXSelectedTextMarkerRange=*"}, R"~~(AXWebArea
+++AXGroup
+++++AXStaticText AXSelectedTextMarkerRange={anchor: {:3, 0, down}, focus: {:2, -1, down}} AXValue='Paragraph'
+)~~");
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityTreeFormatterMacBrowserTest,
                        ParameterizedAttributes) {
   TestAndCheck(R"~~(data:text/html,
                     <table role="grid"><tr><td>CELL</td></tr></table>)~~",
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.h b/content/browser/accessibility/browser_accessibility_cocoa.h
index 701d9aa..8e7b652d 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.h
+++ b/content/browser/accessibility/browser_accessibility_cocoa.h
@@ -31,9 +31,15 @@
 // Returns true if the given object is AXTextMarker object.
 bool IsAXTextMarker(id);
 
+// Returns true if the given object is AXTextMarkerRange object.
+bool IsAXTextMarkerRange(id);
+
 // Returns browser accessibility position for the given AXTextMarker.
 BrowserAccessibilityPosition::AXPositionInstance AXTextMarkerToPosition(id);
 
+// Returns browser accessibility range for the given AXTextMarkerRange.
+BrowserAccessibilityPosition::AXRangeType AXTextMarkerRangeToRange(id);
+
 }  // namespace content
 
 // BrowserAccessibilityCocoa is a cocoa wrapper around the BrowserAccessibility
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 3935fe6..ce1d034 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -317,11 +317,12 @@
 }
 
 AXPlatformRange CreateRangeFromTextMarkerRange(id marker_range) {
+  if (!content::IsAXTextMarkerRange(marker_range)) {
+    return AXPlatformRange();
+  }
+
   AXTextMarkerRangeRef cf_marker_range =
       static_cast<AXTextMarkerRangeRef>(marker_range);
-  DCHECK(cf_marker_range);
-  if (CFGetTypeID(cf_marker_range) != AXTextMarkerRangeGetTypeID())
-    return AXPlatformRange();
 
   base::ScopedCFTypeRef<AXTextMarkerRef> start_marker(
       AXTextMarkerRangeCopyStartMarker(cf_marker_range));
@@ -735,11 +736,26 @@
   return CFGetTypeID(cf_text_marker) == AXTextMarkerGetTypeID();
 }
 
+bool content::IsAXTextMarkerRange(id object) {
+  if (object == nil)
+    return false;
+
+  AXTextMarkerRangeRef cf_marker_range =
+      static_cast<AXTextMarkerRangeRef>(object);
+  DCHECK(cf_marker_range);
+  return CFGetTypeID(cf_marker_range) == AXTextMarkerRangeGetTypeID();
+}
+
 BrowserAccessibilityPosition::AXPositionInstance
 content::AXTextMarkerToPosition(id text_marker) {
   return CreatePositionFromTextMarker(text_marker);
 }
 
+BrowserAccessibilityPosition::AXRangeType
+content::AXTextMarkerRangeToRange(id text_marker_range) {
+  return CreateRangeFromTextMarkerRange(text_marker_range);
+}
+
 @implementation BrowserAccessibilityCocoa
 
 + (void)initialize {
diff --git a/content/browser/appcache/appcache_host_unittest.cc b/content/browser/appcache/appcache_host_unittest.cc
index efc031f..52ed49d 100644
--- a/content/browser/appcache/appcache_host_unittest.cc
+++ b/content/browser/appcache/appcache_host_unittest.cc
@@ -28,6 +28,7 @@
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/test_support/test_utils.h"
 #include "net/url_request/url_request.h"
+#include "storage/browser/quota/quota_client_type.h"
 #include "storage/browser/quota/quota_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
@@ -115,7 +116,8 @@
     MockQuotaManagerProxy() : QuotaManagerProxy(nullptr, nullptr) {}
 
     // Not needed for our tests.
-    void RegisterClient(scoped_refptr<storage::QuotaClient> client) override {}
+    void RegisterClient(scoped_refptr<storage::QuotaClient> client,
+                        storage::QuotaClientType client_type) override {}
     void NotifyStorageAccessed(const url::Origin& origin,
                                blink::mojom::StorageType type) override {}
     void NotifyStorageModified(storage::QuotaClientType client_id,
diff --git a/content/browser/appcache/appcache_quota_client.cc b/content/browser/appcache/appcache_quota_client.cc
index 0b6e6575..edd10c0 100644
--- a/content/browser/appcache/appcache_quota_client.cc
+++ b/content/browser/appcache/appcache_quota_client.cc
@@ -57,10 +57,6 @@
   DCHECK(current_delete_request_callback_.is_null());
 }
 
-storage::QuotaClientType AppCacheQuotaClient::type() const {
-  return storage::QuotaClientType::kAppcache;
-}
-
 void AppCacheQuotaClient::OnQuotaManagerDestroyed() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DeletePendingRequests();
diff --git a/content/browser/appcache/appcache_quota_client.h b/content/browser/appcache/appcache_quota_client.h
index 41ad80d..8031c2a 100644
--- a/content/browser/appcache/appcache_quota_client.h
+++ b/content/browser/appcache/appcache_quota_client.h
@@ -40,7 +40,6 @@
   explicit AppCacheQuotaClient(base::WeakPtr<AppCacheServiceImpl> service);
 
   // QuotaClient method overrides
-  storage::QuotaClientType type() const override;
   void OnQuotaManagerDestroyed() override;
   void GetOriginUsage(const url::Origin& origin,
                       blink::mojom::StorageType type,
diff --git a/content/browser/appcache/appcache_service_impl.cc b/content/browser/appcache/appcache_service_impl.cc
index e81fd0ef..504c8a05 100644
--- a/content/browser/appcache/appcache_service_impl.cc
+++ b/content/browser/appcache/appcache_service_impl.cc
@@ -33,6 +33,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "net/base/completion_once_callback.h"
 #include "net/base/io_buffer.h"
+#include "storage/browser/quota/quota_client_type.h"
 #include "storage/browser/quota/special_storage_policy.h"
 #include "third_party/blink/public/mojom/appcache/appcache_info.mojom.h"
 
@@ -387,7 +388,8 @@
       partition_(std::move(partition)) {
   if (quota_manager_proxy_.get()) {
     quota_client_ = base::MakeRefCounted<AppCacheQuotaClient>(AsWeakPtr());
-    quota_manager_proxy_->RegisterClient(quota_client_);
+    quota_manager_proxy_->RegisterClient(quota_client_,
+                                         storage::QuotaClientType::kAppcache);
   }
 }
 
diff --git a/content/browser/appcache/appcache_storage_impl_unittest.cc b/content/browser/appcache/appcache_storage_impl_unittest.cc
index e4f9c23..7ae97e2 100644
--- a/content/browser/appcache/appcache_storage_impl_unittest.cc
+++ b/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -51,6 +51,7 @@
 #include "net/http/http_response_headers.h"
 #include "services/network/test/test_utils.h"
 #include "sql/test/test_helpers.h"
+#include "storage/browser/quota/quota_client_type.h"
 #include "storage/browser/quota/quota_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
@@ -197,7 +198,8 @@
     }
 
     // Not needed for our tests.
-    void RegisterClient(scoped_refptr<storage::QuotaClient> client) override {}
+    void RegisterClient(scoped_refptr<storage::QuotaClient> client,
+                        storage::QuotaClientType quota_client_type) override {}
     void NotifyOriginInUse(const url::Origin& origin) override {}
     void NotifyOriginNoLongerInUse(const url::Origin& origin) override {}
     void SetUsageCacheEnabled(storage::QuotaClientType client_id,
diff --git a/content/browser/background_fetch/background_fetch_test_data_manager.cc b/content/browser/background_fetch/background_fetch_test_data_manager.cc
index d86550b8..c944d87 100644
--- a/content/browser/background_fetch/background_fetch_test_data_manager.cc
+++ b/content/browser/background_fetch/background_fetch_test_data_manager.cc
@@ -30,7 +30,8 @@
             base::ThreadTaskRunnerHandle::Get().get()) {}
 
   // Ignore quota client, it is irrelevant for these tests.
-  void RegisterClient(scoped_refptr<storage::QuotaClient> client) override {}
+  void RegisterClient(scoped_refptr<storage::QuotaClient> client,
+                      storage::QuotaClientType client_type) override {}
 
   void GetUsageAndQuota(base::SequencedTaskRunner* original_task_runner,
                         const url::Origin& origin,
diff --git a/content/browser/cache_storage/cache_storage_context_impl.cc b/content/browser/cache_storage/cache_storage_context_impl.cc
index d91b597..15a53cb4 100644
--- a/content/browser/cache_storage/cache_storage_context_impl.cc
+++ b/content/browser/cache_storage/cache_storage_context_impl.cc
@@ -19,6 +19,7 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/quota/quota_client_type.h"
 #include "storage/browser/quota/quota_manager_proxy.h"
 #include "storage/browser/quota/special_storage_policy.h"
 #include "url/origin.h"
@@ -318,10 +319,12 @@
     return;
   quota_manager_proxy->RegisterClient(
       base::MakeRefCounted<CacheStorageQuotaClient>(
-          manager, CacheStorageOwner::kCacheAPI));
+          manager, CacheStorageOwner::kCacheAPI),
+      storage::QuotaClientType::kServiceWorkerCache);
   quota_manager_proxy->RegisterClient(
       base::MakeRefCounted<CacheStorageQuotaClient>(
-          manager, CacheStorageOwner::kBackgroundFetch));
+          manager, CacheStorageOwner::kBackgroundFetch),
+      storage::QuotaClientType::kBackgroundFetch);
 }
 
 }  // namespace content
diff --git a/content/browser/cache_storage/cache_storage_manager_unittest.cc b/content/browser/cache_storage/cache_storage_manager_unittest.cc
index e57b1e39..f36165e3 100644
--- a/content/browser/cache_storage/cache_storage_manager_unittest.cc
+++ b/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -48,6 +48,7 @@
 #include "services/network/public/mojom/fetch_api.mojom.h"
 #include "storage/browser/blob/blob_storage_context.h"
 #include "storage/browser/quota/padding_key.h"
+#include "storage/browser/quota/quota_client_type.h"
 #include "storage/browser/quota/quota_manager_proxy.h"
 #include "storage/browser/test/fake_blob.h"
 #include "storage/browser/test/mock_quota_manager_proxy.h"
@@ -171,7 +172,8 @@
                                     base::SingleThreadTaskRunner* task_runner)
       : MockQuotaManagerProxy(quota_manager, task_runner) {}
 
-  void RegisterClient(scoped_refptr<storage::QuotaClient> client) override {
+  void RegisterClient(scoped_refptr<storage::QuotaClient> client,
+                      storage::QuotaClientType client_type) override {
     registered_clients_.push_back(std::move(client));
   }
 
@@ -2519,11 +2521,6 @@
   TestManager ManagerType() override { return GetParam().manager_; }
 };
 
-TEST_P(CacheStorageQuotaClientTestP, QuotaID) {
-  EXPECT_EQ(storage::QuotaClientType::kServiceWorkerCache,
-            quota_client_->type());
-}
-
 TEST_P(CacheStorageQuotaClientTestP, QuotaGetOriginUsage) {
   EXPECT_EQ(0, QuotaGetOriginUsage(origin1_));
   EXPECT_TRUE(Open(origin1_, "foo"));
diff --git a/content/browser/cache_storage/cache_storage_quota_client.cc b/content/browser/cache_storage/cache_storage_quota_client.cc
index 2f87d3c..2e6ec9e 100644
--- a/content/browser/cache_storage/cache_storage_quota_client.cc
+++ b/content/browser/cache_storage/cache_storage_quota_client.cc
@@ -19,11 +19,6 @@
 
 CacheStorageQuotaClient::~CacheStorageQuotaClient() = default;
 
-storage::QuotaClientType CacheStorageQuotaClient::type() const {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  return GetClientTypeFromOwner(owner_);
-}
-
 void CacheStorageQuotaClient::OnQuotaManagerDestroyed() {}
 
 void CacheStorageQuotaClient::GetOriginUsage(const url::Origin& origin,
diff --git a/content/browser/cache_storage/cache_storage_quota_client.h b/content/browser/cache_storage/cache_storage_quota_client.h
index 7719a61..5374f0a 100644
--- a/content/browser/cache_storage/cache_storage_quota_client.h
+++ b/content/browser/cache_storage/cache_storage_quota_client.h
@@ -27,7 +27,6 @@
                           CacheStorageOwner owner);
 
   // QuotaClient.
-  storage::QuotaClientType type() const override;
   void OnQuotaManagerDestroyed() override;
   void GetOriginUsage(const url::Origin& origin,
                       blink::mojom::StorageType type,
diff --git a/content/browser/find_request_manager.cc b/content/browser/find_request_manager.cc
index 102d0d30..9376c9b 100644
--- a/content/browser/find_request_manager.cc
+++ b/content/browser/find_request_manager.cc
@@ -278,7 +278,7 @@
   DCHECK_GT(request_id, current_session_id_);
 
   // If this is a new find session, clear any queued requests from last session.
-  if (!options->find_next)
+  if (options->new_session)
     find_request_queue_ = base::queue<FindRequest>();
 
   find_request_queue_.emplace(request_id, search_text, std::move(options));
@@ -327,7 +327,7 @@
 
   // This is the final update for all frames for the current find operation.
   if (request_id == current_request_.id && request_id != current_session_id_) {
-    DCHECK(current_request_.options->find_next);
+    DCHECK(!current_request_.options->new_session);
     DCHECK_EQ(pending_find_next_reply_, rfh);
     pending_find_next_reply_ = nullptr;
   }
@@ -584,7 +584,7 @@
   DCHECK_GT(request.id, current_request_.id);
   DCHECK_GT(request.id, current_session_id_);
 
-  if (request.options->find_next) {
+  if (!request.options->new_session) {
     // This is a find next operation.
 
     // This implies that there is an ongoing find session with the same search
@@ -636,10 +636,10 @@
   DCHECK(CheckFrame(rfh));
   DCHECK(rfh->IsRenderFrameLive());
 
-  if (request.options->find_next)
-    pending_find_next_reply_ = rfh;
-  else
+  if (request.options->new_session)
     pending_initial_replies_.insert(rfh);
+  else
+    pending_find_next_reply_ = rfh;
 
   static_cast<RenderFrameHostImpl*>(rfh)->GetFindInPage()->Find(
       request.id, base::UTF16ToUTF8(request.search_text),
@@ -721,7 +721,7 @@
 
   FindRequest request = current_request_;
   request.id = current_session_id_;
-  request.options->find_next = false;
+  request.options->new_session = true;
   request.options->force = force;
   SendFindRequest(request, rfh);
 }
@@ -770,7 +770,7 @@
 
   RenderFrameHost* target_rfh;
   if (request_id == current_request_.id &&
-      current_request_.options->find_next) {
+      !current_request_.options->new_session) {
     // If this was a find next operation, then the active match will be in the
     // next frame with matches after this one.
     target_rfh = Traverse(rfh, current_request_.options->forward,
@@ -804,7 +804,7 @@
   // has not yet been found.
   NotifyFindReply(request_id, false /* final_update */);
 
-  current_request_.options->find_next = true;
+  current_request_.options->new_session = false;
   SendFindRequest(current_request_, target_rfh);
 }
 
diff --git a/content/browser/find_request_manager_browsertest.cc b/content/browser/find_request_manager_browsertest.cc
index 0fe3de7..10667a70 100644
--- a/content/browser/find_request_manager_browsertest.cc
+++ b/content/browser/find_request_manager_browsertest.cc
@@ -173,7 +173,7 @@
   EXPECT_EQ(19, results.number_of_matches);
   EXPECT_EQ(1, results.active_match_ordinal);
 
-  options->find_next = true;
+  options->new_session = false;
   for (int i = 2; i <= 10; ++i) {
     Find("result", options->Clone());
     delegate()->WaitForFinalReply();
@@ -343,7 +343,7 @@
   options->run_synchronously_for_testing = true;
   Find("result", options.Clone());
 
-  options->find_next = true;
+  options->new_session = false;
   for (int i = 2; i <= 1000; ++i)
     Find("result", options.Clone());
   delegate()->WaitForFinalReply();
@@ -364,7 +364,7 @@
   options->run_synchronously_for_testing = true;
   Find("result", options->Clone());
   delegate()->WaitForFinalReply();
-  options->find_next = true;
+  options->new_session = false;
   options->forward = false;
   Find("result", options->Clone());
   Find("result", options->Clone());
@@ -396,7 +396,7 @@
   options->run_synchronously_for_testing = true;
   Find("result", options->Clone());
   delegate()->WaitForFinalReply();
-  options->find_next = true;
+  options->new_session = false;
   options->forward = false;
   Find("result", options->Clone());
   Find("result", options->Clone());
@@ -416,7 +416,7 @@
   auto options = blink::mojom::FindOptions::New();
   options->run_synchronously_for_testing = true;
   Find("result", options.Clone());
-  options->find_next = true;
+  options->new_session = false;
   Find("result", options.Clone());
   Find("result", options.Clone());
   Find("result", options.Clone());
@@ -489,7 +489,7 @@
   auto options = blink::mojom::FindOptions::New();
   options->run_synchronously_for_testing = true;
   Find("result", options.Clone());
-  options->find_next = true;
+  options->new_session = false;
   options->forward = false;
   Find("result", options.Clone());
   Find("result", options.Clone());
@@ -553,7 +553,7 @@
   auto options = blink::mojom::FindOptions::New();
   options->run_synchronously_for_testing = true;
   Find("result", options.Clone());
-  options->find_next = true;
+  options->new_session = false;
   Find("result", options.Clone());
   Find("result", options.Clone());
   delegate()->WaitForFinalReply();
@@ -599,7 +599,7 @@
   EXPECT_EQ(1, results.active_match_ordinal);
 
   delegate()->StartReplyRecord();
-  options->find_next = true;
+  options->new_session = false;
   options->forward = false;
   Find("42", options.Clone());
   delegate()->WaitForFinalReply();
@@ -885,7 +885,7 @@
     // Iterate forward/backward over a few elements.
     int match_index = results.active_match_ordinal;
     for (int delta : {-1, -1, +1, +1, +1, +1, -1, +1, +1}) {
-      options->find_next = true;
+      options->new_session = false;
       options->forward = delta > 0;
       // |active_match_ordinal| uses 1-based index. It belongs to [1, 19].
       match_index += delta;
diff --git a/content/browser/form_controls_browsertest.cc b/content/browser/form_controls_browsertest.cc
index 2282130..8271717 100644
--- a/content/browser/form_controls_browsertest.cc
+++ b/content/browser/form_controls_browsertest.cc
@@ -137,7 +137,14 @@
   std::unique_ptr<base::test::ScopedFeatureList> feature_list_;
 };
 
-IN_PROC_BROWSER_TEST_F(FormControlsBrowserTest, Checkbox) {
+#if defined(OS_ANDROID)
+#define DISABLED_ON_ANDROID(name) DISABLED##name
+#else
+#define DISABLED_ON_ANDROID(name) name
+#endif
+
+// Flaky: https://crbug.com/1091661
+IN_PROC_BROWSER_TEST_F(FormControlsBrowserTest, DISABLED_ON_ANDROID(Checkbox)) {
   RunFormControlsTest(
       "form_controls_browsertest_checkbox",
       "<input type=checkbox>"
@@ -152,7 +159,8 @@
       /* screenshot_height */ 40);
 }
 
-IN_PROC_BROWSER_TEST_F(FormControlsBrowserTest, Radio) {
+// Flaky: https://crbug.com/1091661
+IN_PROC_BROWSER_TEST_F(FormControlsBrowserTest, DISABLED_ON_ANDROID(Radio)) {
   RunFormControlsTest(
       "form_controls_browsertest_radio",
       "<input type=radio>"
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 914d8ffb..ddf319a 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -46,6 +46,7 @@
 #include "content/browser/loader/cached_navigation_url_loader.h"
 #include "content/browser/loader/navigation_url_loader.h"
 #include "content/browser/net/cross_origin_embedder_policy_reporter.h"
+#include "content/browser/net/cross_origin_opener_policy_reporter.h"
 #include "content/browser/network_service_instance_impl.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_delegate.h"
@@ -101,6 +102,7 @@
 #include "services/network/public/cpp/content_security_policy/content_security_policy.h"
 #include "services/network/public/cpp/cross_origin_resource_policy.h"
 #include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "services/network/public/cpp/resource_request_body.h"
 #include "services/network/public/cpp/url_loader_completion_status.h"
 #include "services/network/public/cpp/web_sandbox_flags.h"
@@ -1553,6 +1555,37 @@
   return std::move(coep_reporter_);
 }
 
+void NavigationRequest::CreateCoopReporter(
+    StoragePartition* storage_partition) {
+  // If the flag for reporting is off, we simply don't create anything.
+  // Since this is the only place we create COOP reporters this ensure reporting
+  // is completely off.
+  // Note that "popup inheritance" also instantiate a reporter, but only if we
+  // created one here first.
+  if (!base::FeatureList::IsEnabled(
+          network::features::kCrossOriginOpenerPolicyReporting)) {
+    return;
+  }
+
+  // If the page does not have any reporting endpoints, skip creating a
+  // reporter.
+  if (!render_frame_host_->cross_origin_opener_policy().reporting_endpoint &&
+      !render_frame_host_->cross_origin_opener_policy()
+           .report_only_reporting_endpoint) {
+    return;
+  }
+
+  coop_reporter_ = std::make_unique<CrossOriginOpenerPolicyReporter>(
+      storage_partition, frame_tree_node_->current_frame_host(),
+      common_params_->url, render_frame_host_->cross_origin_opener_policy(),
+      render_frame_host_->cross_origin_embedder_policy());
+}
+
+std::unique_ptr<CrossOriginOpenerPolicyReporter>
+NavigationRequest::TakeCoopReporter() {
+  return std::move(coop_reporter_);
+}
+
 ukm::SourceId NavigationRequest::GetPreviousPageUkmSourceId() {
   return previous_page_load_ukm_source_id_;
 }
@@ -2063,49 +2096,58 @@
       response_head_->parsed_headers->cross_origin_embedder_policy;
   if (base::FeatureList::IsEnabled(
           network::features::kCrossOriginEmbedderPolicy)) {
-    // https://mikewest.github.io/corpp/#process-navigation-response
-    if (auto* const parent_frame = GetParentFrame()) {
-      const auto& parent_coep = parent_frame->cross_origin_embedder_policy();
-      const auto& url = common_params_->url;
-      constexpr auto kRequireCorp =
-          network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
-      constexpr auto kNone =
-          network::mojom::CrossOriginEmbedderPolicyValue::kNone;
+    const auto& url = common_params_->url;
+    // https://w3c.github.io/webappsec-secure-contexts/#is-url-trustworthy
+    // returns "Potentially Trustworthy" for data URLs, but
+    // network::IsUrlPotentiallyTrustworthy returns false, so we need this
+    // extra condition.
+    if (network::IsUrlPotentiallyTrustworthy(url) ||
+        url.SchemeIs(url::kDataScheme)) {
+      // https://mikewest.github.io/corpp/#process-navigation-response
+      if (auto* const parent = GetParentFrame()) {
+        const auto& parent_coep = parent->cross_origin_embedder_policy();
+        constexpr auto kRequireCorp =
+            network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
+        constexpr auto kNone =
+            network::mojom::CrossOriginEmbedderPolicyValue::kNone;
 
-      // Some special URLs not loaded using the network are inheriting the
-      // Cross-Origin-Embedder-Policy header from their parent.
-      const bool has_allowed_scheme =
-          url.SchemeIsBlob() || url.SchemeIs(url::kDataScheme) ||
-          GetContentClient()
-              ->browser()
-              ->ShouldInheritCrossOriginEmbedderPolicyImplicitly(url);
-      if (parent_coep.value == kRequireCorp && has_allowed_scheme) {
-        cross_origin_embedder_policy.value = kRequireCorp;
-      }
-
-      auto* const coep_reporter = parent_frame->coep_reporter();
-      if (parent_coep.report_only_value == kRequireCorp &&
-          !has_allowed_scheme && cross_origin_embedder_policy.value == kNone &&
-          coep_reporter) {
-        coep_reporter->QueueNavigationReport(redirect_chain_[0],
-                                             /*report_only=*/true);
-      }
-      if (parent_coep.value == kRequireCorp &&
-          cross_origin_embedder_policy.value == kNone) {
-        if (coep_reporter) {
-          coep_reporter->QueueNavigationReport(redirect_chain_[0],
-                                               /*report_only=*/false);
+        // Some special URLs not loaded using the network are inheriting the
+        // Cross-Origin-Embedder-Policy header from their parent.
+        const bool has_allowed_scheme =
+            url.SchemeIsBlob() || url.SchemeIs(url::kDataScheme) ||
+            GetContentClient()
+                ->browser()
+                ->ShouldInheritCrossOriginEmbedderPolicyImplicitly(url);
+        if (parent_coep.value == kRequireCorp && has_allowed_scheme) {
+          cross_origin_embedder_policy.value = kRequireCorp;
         }
-        OnRequestFailedInternal(network::URLLoaderCompletionStatus(
-                                    network::mojom::BlockedByResponseReason::
-                                        kCoepFrameResourceNeedsCoepHeader),
-                                false /* skip_throttles */,
-                                base::nullopt /* error_page_content */,
-                                false /* collapse_frame */);
-        // DO NOT ADD CODE after this. The previous call to
-        // OnRequestFailedInternal has destroyed the NavigationRequest.
-        return;
+
+        auto* const coep_reporter = parent->coep_reporter();
+        if (parent_coep.report_only_value == kRequireCorp &&
+            !has_allowed_scheme &&
+            cross_origin_embedder_policy.value == kNone && coep_reporter) {
+          coep_reporter->QueueNavigationReport(redirect_chain_[0],
+                                               /*report_only=*/true);
+        }
+        if (parent_coep.value == kRequireCorp &&
+            cross_origin_embedder_policy.value == kNone) {
+          if (coep_reporter) {
+            coep_reporter->QueueNavigationReport(redirect_chain_[0],
+                                                 /*report_only=*/false);
+          }
+          OnRequestFailedInternal(network::URLLoaderCompletionStatus(
+                                      network::mojom::BlockedByResponseReason::
+                                          kCoepFrameResourceNeedsCoepHeader),
+                                  false /* skip_throttles */,
+                                  base::nullopt /* error_page_content */,
+                                  false /* collapse_frame */);
+          // DO NOT ADD CODE after this. The previous call to
+          // OnRequestFailedInternal has destroyed the NavigationRequest.
+          return;
+        }
       }
+    } else {
+      cross_origin_embedder_policy = network::CrossOriginEmbedderPolicy();
     }
   }
 
@@ -2976,6 +3018,7 @@
 
   sandbox_flags_to_commit_ = ComputeSandboxFlagsToCommit();
   CreateCoepReporter(render_frame_host_->GetProcess()->GetStoragePartition());
+  CreateCoopReporter(render_frame_host_->GetProcess()->GetStoragePartition());
 
   blink::mojom::ServiceWorkerContainerInfoForClientPtr
       service_worker_container_info;
@@ -3807,7 +3850,7 @@
   // The renderer already knows locally about it because we sent an empty name
   // at frame creation time. The renderer has now committed the page and we can
   // safely enforce the empty name on the browser side.
-  if (require_coop_browsing_instance_swap()) {
+  if (coop_status().require_browsing_instance_swap) {
     std::string name, unique_name;
     // "COOP swaps" only affect main frames, that have an empty unique name.
     DCHECK(frame_tree_node_->unique_name().empty());
@@ -4587,4 +4630,8 @@
   return out;
 }
 
+CrossOriginOpenerPolicyStatus& NavigationRequest::coop_status() {
+  return coop_status_;
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index 921da7c..fc324ba7c 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -63,6 +63,7 @@
 
 class AppCacheNavigationHandle;
 class CrossOriginEmbedderPolicyReporter;
+class CrossOriginOpenerPolicyReporter;
 class WebBundleHandleTracker;
 class WebBundleNavigationInfo;
 class FrameNavigationEntry;
@@ -75,6 +76,26 @@
 class SiteInstanceImpl;
 struct SubresourceLoaderParams;
 
+// A structure that groups information about how COOP has interacted with the
+// navigation. These are used to trigger a number of mechanisms such as name
+// clearing or reporting.
+struct CrossOriginOpenerPolicyStatus {
+  // Set to true whenever the Cross-Origin-Opener-Policy spec requires a
+  // "BrowsingContext group" swap:
+  // https://gist.github.com/annevk/6f2dd8c79c77123f39797f6bdac43f3e
+  // This forces the new RenderFrameHost to use a different BrowsingInstance
+  // than the current one. If other pages had JavaScript references to the
+  // Window object for the frame (via window.opener, window.open(), et cetera),
+  // those references will be broken; window.name will also be reset to an empty
+  // string.
+  bool require_browsing_instance_swap = false;
+
+  // When a page has a reachable opener and COOP triggers a browsing instance
+  // swap we potentially break the page. This is one of the case that can be
+  // reported using the COOP reporting API.
+  bool had_opener_before_browsing_instance_swap = false;
+};
+
 // A UI thread object that owns a navigation request until it commits. It
 // ensures the UI thread can start a navigation request in the
 // ResourceDispatcherHost (that lives on the IO thread).
@@ -596,20 +617,17 @@
   }
   network::mojom::ClientSecurityStatePtr TakeClientSecurityState();
 
-  bool require_coop_browsing_instance_swap() const {
-    return require_coop_browsing_instance_swap_;
-  }
-
   bool ua_change_requires_reload() const { return ua_change_requires_reload_; }
 
-  void set_require_coop_browsing_instance_swap() {
-    require_coop_browsing_instance_swap_ = true;
-  }
   CrossOriginEmbedderPolicyReporter* coep_reporter() {
     return coep_reporter_.get();
   }
+  CrossOriginOpenerPolicyReporter* coop_reporter() {
+    return coop_reporter_.get();
+  }
 
   std::unique_ptr<CrossOriginEmbedderPolicyReporter> TakeCoepReporter();
+  std::unique_ptr<CrossOriginOpenerPolicyReporter> TakeCoopReporter();
 
   // Returns UKM SourceId for the page we are navigating away from.
   // Equal to GetRenderFrameHost()->GetPageUkmSourceId() for subframe
@@ -638,6 +656,9 @@
   // directly into the RenderDocumentHost.
   base::Optional<network::mojom::WebSandboxFlags> SandboxFlagsToCommit();
 
+  // Returns the coop status information relevant to the current navigation.
+  CrossOriginOpenerPolicyStatus& coop_status();
+
  private:
   friend class NavigationRequestTest;
 
@@ -959,6 +980,7 @@
   void ForceEnableOriginTrials(const std::vector<std::string>& trials) override;
 
   void CreateCoepReporter(StoragePartition* storage_partition);
+  void CreateCoopReporter(StoragePartition* storage_partition);
 
   base::Optional<network::mojom::BlockedByResponseReason> IsBlockedByCorp();
 
@@ -1306,22 +1328,13 @@
   network::mojom::ClientSecurityStatePtr client_security_state_;
 
   std::unique_ptr<CrossOriginEmbedderPolicyReporter> coep_reporter_;
+  std::unique_ptr<CrossOriginOpenerPolicyReporter> coop_reporter_;
 
   std::unique_ptr<PeakGpuMemoryTracker> loading_mem_tracker_ = nullptr;
 
-  // Set to true whenever we the Cross-Origin-Opener-Policy spec requires us to
-  // do a "BrowsingContext group" swap:
-  // https://gist.github.com/annevk/6f2dd8c79c77123f39797f6bdac43f3e
-  // This forces a new BrowsingInstance to be used for the RenderFrameHost the
-  // navigation will commit in. If other pages had JavaScript references to the
-  // Window object for the frame (via window.opener, window.open(), et cetera),
-  // those references will be broken; window.name will also be reset to an empty
-  // string.
-  // TODO(ahemery): COOP requires that any page during the redirect chain
-  // having an incompatible COOP triggers a BrowsingInstance swap. Even if the
-  // end document could be put in the same BrowsingInstance as the starting
-  // one. Implement the behavior.
-  bool require_coop_browsing_instance_swap_ = false;
+  // Structure tracking the effects of the CrossOriginOpenerPolicy on this
+  // navigation.
+  CrossOriginOpenerPolicyStatus coop_status_;
 
 #if DCHECK_IS_ON()
   bool is_safe_to_delete_ = true;
diff --git a/content/browser/frame_host/navigator.cc b/content/browser/frame_host/navigator.cc
index c439328..3c3dac7 100644
--- a/content/browser/frame_host/navigator.cc
+++ b/content/browser/frame_host/navigator.cc
@@ -235,8 +235,8 @@
   frame_tree_node->render_manager()->DidNavigateFrame(
       render_frame_host, params.gesture == NavigationGestureUser,
       is_same_document_navigation,
-      navigation_request
-          ->require_coop_browsing_instance_swap() /* clear_proxies_on_commit */,
+      navigation_request->coop_status()
+          .require_browsing_instance_swap /* clear_proxies_on_commit */,
       pending_frame_policy);
 
   // Save the new page's origin and other properties, and replicate them to
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index c1662e52..7b677cd 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -82,6 +82,7 @@
 #include "content/browser/native_file_system/native_file_system_manager_impl.h"
 #include "content/browser/navigation_subresource_loader_params.h"
 #include "content/browser/net/cross_origin_embedder_policy_reporter.h"
+#include "content/browser/net/cross_origin_opener_policy_reporter.h"
 #include "content/browser/payments/payment_app_context_impl.h"
 #include "content/browser/permissions/permission_controller_impl.h"
 #include "content/browser/permissions/permission_service_context.h"
@@ -2115,7 +2116,7 @@
   NavigationRequest* navigation_request =
       frame_tree_node()->navigation_request();
   if (navigation_request &&
-      navigation_request->require_coop_browsing_instance_swap()) {
+      navigation_request->coop_status().require_browsing_instance_swap) {
     params->replication_state.name = "";
     // "COOP swaps" only affect main frames, that have an empty unique name.
     DCHECK(params->replication_state.unique_name.empty());
@@ -4862,6 +4863,16 @@
   main_frame->cross_origin_opener_policy_ = popup_coop;
   main_frame->cross_origin_embedder_policy_ = popup_coep;
 
+  // If inheriting coop (checking this via |opener_suppressed|) and the original
+  // coop page has a reporter we make sure the the newly created popup also has
+  // a reporter.
+  if (!params->opener_suppressed && GetMainFrame()->coop_reporter()) {
+    main_frame->set_coop_reporter(
+        std::make_unique<CrossOriginOpenerPolicyReporter>(
+            GetProcess()->GetStoragePartition(), this, GetLastCommittedURL(),
+            popup_coop, popup_coep));
+  }
+
   if (main_frame->waiting_for_init_) {
     // Need to check |waiting_for_init_| as some paths inside CreateNewWindow
     // call above (eg if WebContentsDelegate::IsWebContentsCreationOverridden()
@@ -8075,6 +8086,21 @@
                        weak_ptr_factory_.GetWeakPtr(), std::move(receiver)));
   }
 
+  std::unique_ptr<CrossOriginOpenerPolicyReporter> coop_reporter =
+      navigation_request->TakeCoopReporter();
+
+  // If this navigation had a COOP BrowsingInstance swap that severed an opener,
+  // and we have a reporter on the page we're going to, report it here.
+  if (navigation_request->coop_status()
+          .had_opener_before_browsing_instance_swap &&
+      coop_reporter) {
+    coop_reporter->QueueOpenerBreakageReport(
+        coop_reporter->GetPreviousDocumentUrlForReporting(
+            navigation_request->GetRedirectChain(),
+            navigation_request->common_params().referrer->url),
+        false /* is_reported_from_document */, false /* is_report_only */);
+  }
+
   frame_tree_node()->navigator().DidNavigate(this, *params,
                                              std::move(navigation_request),
                                              is_same_document_navigation);
@@ -8095,6 +8121,7 @@
     browser_reported_scheduler_tracked_features_ = 0;
     last_committed_client_security_state_ = std::move(client_security_state);
     coep_reporter_ = std::move(coep_reporter);
+    coop_reporter_ = std::move(coop_reporter);
   }
 
   RecordCrossOriginIsolationMetrics(this);
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index b0553a50..48ceca84 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -39,6 +39,7 @@
 #include "content/browser/feature_observer.h"
 #include "content/browser/frame_host/back_forward_cache_metrics.h"
 #include "content/browser/frame_host/should_swap_browsing_instance.h"
+#include "content/browser/net/cross_origin_opener_policy_reporter.h"
 #include "content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h"
 #include "content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h"
 #include "content/browser/site_instance_impl.h"
@@ -1420,6 +1421,10 @@
   CrossOriginEmbedderPolicyReporter* coep_reporter() {
     return coep_reporter_.get();
   }
+  void set_coop_reporter(
+      std::unique_ptr<CrossOriginOpenerPolicyReporter>&& reporter) {
+    coop_reporter_ = std::move(reporter);
+  }
 
   // Semi-formal definition of COOP:
   // https://gist.github.com/annevk/6f2dd8c79c77123f39797f6bdac43f3e
@@ -1429,6 +1434,9 @@
   void set_cross_origin_opener_policy(network::CrossOriginOpenerPolicy policy) {
     cross_origin_opener_policy_ = policy;
   }
+  CrossOriginOpenerPolicyReporter* coop_reporter() {
+    return coop_reporter_.get();
+  }
 
   const network::mojom::ClientSecurityStatePtr&
   last_committed_client_security_state() const {
@@ -3032,6 +3040,7 @@
   base::TimeTicks last_xr_overlay_setup_time_;
 
   std::unique_ptr<CrossOriginEmbedderPolicyReporter> coep_reporter_;
+  std::unique_ptr<CrossOriginOpenerPolicyReporter> coop_reporter_;
 
   // Navigation ID for the last committed cross-document non-bfcached navigation
   // in this RenderFrameHost.
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 2e4d2b3b..08bcfad 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -35,6 +35,7 @@
 #include "content/browser/frame_host/render_frame_host_factory.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/frame_host/render_frame_proxy_host.h"
+#include "content/browser/net/cross_origin_opener_policy_reporter.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_factory.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
@@ -883,7 +884,7 @@
         navigation_rfh->SwapIn();
       navigation_rfh->OnCommittedSpeculativeBeforeNavigationCommit();
       CommitPending(std::move(speculative_render_frame_host_), nullptr,
-                    request->require_coop_browsing_instance_swap());
+                    request->coop_status().require_browsing_instance_swap);
     }
   }
   DCHECK(navigation_rfh &&
@@ -2476,8 +2477,21 @@
           !render_frame_host_->has_committed_any_navigation(), coop, coep,
           url::Origin::Create(request->common_params().url));
 
-  if (cross_origin_policy_swap)
-    request->set_require_coop_browsing_instance_swap();
+  if (cross_origin_policy_swap) {
+    request->coop_status().require_browsing_instance_swap = true;
+    if (frame_tree_node_->opener()) {
+      request->coop_status().had_opener_before_browsing_instance_swap = true;
+      // TODO(ahemery): Redirects should be able to report.
+      if (render_frame_host_->coop_reporter() &&
+          request->state() >
+              NavigationRequest::NavigationState::WILL_REDIRECT_REQUEST) {
+        render_frame_host_->coop_reporter()->QueueOpenerBreakageReport(
+            render_frame_host_->coop_reporter()->GetNextDocumentUrlForReporting(
+                request->GetRedirectChain(), request->GetInitiatorRoutingId()),
+            true /* is_reported_from_document */, false /* is_report_only */);
+      }
+    }
+  }
 
   scoped_refptr<SiteInstance> dest_site_instance = GetSiteInstanceForNavigation(
       request->common_params().url, request->GetSourceSiteInstance(),
@@ -2486,7 +2500,7 @@
       request->state() >= NavigationRequest::CANCELING, is_reload,
       request->GetRestoreType() != RestoreType::NONE, request->is_view_source(),
       request->WasServerRedirect(),
-      request->require_coop_browsing_instance_swap());
+      request->coop_status().require_browsing_instance_swap);
 
   // If the NavigationRequest's dest_site_instance was present but incorrect,
   // then ensure no sensitive state is kept on the request. This can happen for
diff --git a/content/browser/geolocation/geolocation_service_impl.cc b/content/browser/geolocation/geolocation_service_impl.cc
index 8a8ef43..7e53cb9 100644
--- a/content/browser/geolocation/geolocation_service_impl.cc
+++ b/content/browser/geolocation/geolocation_service_impl.cc
@@ -11,6 +11,7 @@
 #include "content/public/browser/permission_type.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
 #include "mojo/public/cpp/bindings/callback_helpers.h"
 #include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom.h"
 
@@ -103,7 +104,11 @@
   if (permission_status != blink::mojom::PermissionStatus::GRANTED)
     return;
 
-  geolocation_context_->BindGeolocation(std::move(receiver));
+  WebContents* web_contents =
+      WebContents::FromRenderFrameHost(render_frame_host_);
+
+  geolocation_context_->BindGeolocation(
+      std::move(receiver), web_contents->GetLastCommittedURL().GetOrigin());
 }
 
 }  // namespace content
diff --git a/content/browser/indexed_db/indexed_db_context_impl.cc b/content/browser/indexed_db/indexed_db_context_impl.cc
index f6fc1de..65b9519 100644
--- a/content/browser/indexed_db/indexed_db_context_impl.cc
+++ b/content/browser/indexed_db/indexed_db_context_impl.cc
@@ -41,6 +41,7 @@
 #include "content/browser/indexed_db/indexed_db_transaction.h"
 #include "content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h"
 #include "storage/browser/database/database_util.h"
+#include "storage/browser/quota/quota_client_type.h"
 #include "storage/common/database/database_identifier.h"
 #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
@@ -132,7 +133,8 @@
   if (!data_path.empty())
     data_path_ = data_path.Append(kIndexedDBDirectory);
   quota_manager_proxy->RegisterClient(
-      base::MakeRefCounted<IndexedDBQuotaClient>(this));
+      base::MakeRefCounted<IndexedDBQuotaClient>(this),
+      storage::QuotaClientType::kIndexedDatabase);
 
   // This is safe because the IndexedDBContextImpl must be destructed on the
   // IDBTaskRunner, and this task will always happen before that.
diff --git a/content/browser/indexed_db/indexed_db_quota_client.cc b/content/browser/indexed_db/indexed_db_quota_client.cc
index f35ae3d..946596d 100644
--- a/content/browser/indexed_db/indexed_db_quota_client.cc
+++ b/content/browser/indexed_db/indexed_db_quota_client.cc
@@ -78,10 +78,6 @@
 
 IndexedDBQuotaClient::~IndexedDBQuotaClient() = default;
 
-storage::QuotaClientType IndexedDBQuotaClient::type() const {
-  return storage::QuotaClientType::kIndexedDatabase;
-}
-
 void IndexedDBQuotaClient::OnQuotaManagerDestroyed() {}
 
 void IndexedDBQuotaClient::GetOriginUsage(const url::Origin& origin,
diff --git a/content/browser/indexed_db/indexed_db_quota_client.h b/content/browser/indexed_db/indexed_db_quota_client.h
index fe85dc97..3e9b48b 100644
--- a/content/browser/indexed_db/indexed_db_quota_client.h
+++ b/content/browser/indexed_db/indexed_db_quota_client.h
@@ -30,7 +30,6 @@
       scoped_refptr<IndexedDBContextImpl> indexed_db_context);
 
   // QuotaClient implementation:
-  storage::QuotaClientType type() const override;
   void OnQuotaManagerDestroyed() override;
   void GetOriginUsage(const url::Origin& origin,
                       blink::mojom::StorageType type,
diff --git a/content/browser/net/cross_origin_opener_policy_reporter.cc b/content/browser/net/cross_origin_opener_policy_reporter.cc
new file mode 100644
index 0000000..9721f1a
--- /dev/null
+++ b/content/browser/net/cross_origin_opener_policy_reporter.cc
@@ -0,0 +1,192 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/net/cross_origin_opener_policy_reporter.h"
+
+#include "base/values.h"
+#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/public/browser/storage_partition.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+
+namespace content {
+
+namespace {
+
+constexpr char kUnsafeNone[] = "unsafe-none";
+constexpr char kSameOrigin[] = "same-origin";
+constexpr char kSameOriginPlusCoep[] = "same-origin-plus-coep";
+constexpr char kSameOriginAllowPopups[] = "same-origin-allow-popups";
+
+constexpr char kDisposition[] = "disposition";
+constexpr char kDispositionEnforce[] = "enforce";
+constexpr char kDispositionReporting[] = "reporting";
+constexpr char kDocumentURI[] = "document-uri";
+constexpr char kNavigationURI[] = "navigation-uri";
+constexpr char kViolationType[] = "violation-type";
+constexpr char kViolationTypeFromDocument[] = "navigation-from-document";
+constexpr char kViolationTypeToDocument[] = "navigation-to-document";
+constexpr char kEffectivePolicy[] = "effective-policy";
+
+std::string CoopValueToString(
+    network::mojom::CrossOriginOpenerPolicyValue coop_value,
+    network::mojom::CrossOriginEmbedderPolicyValue coep_value,
+    network::mojom::CrossOriginEmbedderPolicyValue report_only_coep_value) {
+  switch (coop_value) {
+    case network::mojom::CrossOriginOpenerPolicyValue::kUnsafeNone:
+      return kUnsafeNone;
+    case network::mojom::CrossOriginOpenerPolicyValue::kSameOrigin:
+      if ((coep_value ==
+           network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp) ||
+          (report_only_coep_value ==
+           network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp)) {
+        return kSameOriginPlusCoep;
+      }
+      return kSameOrigin;
+    case network::mojom::CrossOriginOpenerPolicyValue::kSameOriginAllowPopups:
+      return kSameOriginAllowPopups;
+  }
+}
+
+RenderFrameHostImpl* GetSourceRfhForCoopReporting(
+    RenderFrameHostImpl* current_rfh) {
+  CHECK(current_rfh);
+
+  // If this is a fresh popup we would consider the source RFH to be
+  // our opener.
+  if (!current_rfh->has_committed_any_navigation())
+    return current_rfh->frame_tree_node()->opener()->current_frame_host();
+
+  // Otherwise this is simply the current RFH.
+  return current_rfh;
+}
+
+}  // namespace
+
+CrossOriginOpenerPolicyReporter::CrossOriginOpenerPolicyReporter(
+    StoragePartition* storage_partition,
+    RenderFrameHostImpl* current_rfh,
+    const GURL& context_url,
+    const network::CrossOriginOpenerPolicy& coop,
+    const network::CrossOriginEmbedderPolicy& coep)
+    : storage_partition_(storage_partition),
+      context_url_(context_url),
+      coop_(coop),
+      coep_(coep) {
+  DCHECK(storage_partition_);
+  RenderFrameHostImpl* source_rfh = GetSourceRfhForCoopReporting(current_rfh);
+  source_url_ = source_rfh->GetLastCommittedURL();
+  source_routing_id_.child_id = source_rfh->GetProcess()->GetID();
+  source_routing_id_.frame_routing_id = source_rfh->GetRoutingID();
+}
+
+CrossOriginOpenerPolicyReporter::CrossOriginOpenerPolicyReporter(
+    StoragePartition* storage_partition,
+    const GURL& source_url,
+    const GlobalFrameRoutingId source_routing_id,
+    const GURL& context_url,
+    const network::CrossOriginOpenerPolicy& coop,
+    const network::CrossOriginEmbedderPolicy& coep)
+    : storage_partition_(storage_partition),
+      source_url_(source_url),
+      source_routing_id_(source_routing_id),
+      context_url_(context_url),
+      coop_(coop),
+      coep_(coep) {
+  DCHECK(storage_partition_);
+}
+
+CrossOriginOpenerPolicyReporter::~CrossOriginOpenerPolicyReporter() = default;
+
+void CrossOriginOpenerPolicyReporter::QueueOpenerBreakageReport(
+    const GURL& other_url,
+    bool is_reported_from_document,
+    bool is_report_only) {
+  const base::Optional<std::string>& endpoint =
+      is_report_only ? coop_.report_only_reporting_endpoint
+                     : coop_.reporting_endpoint;
+  DCHECK(endpoint);
+
+  url::Replacements<char> replacements;
+  replacements.ClearUsername();
+  replacements.ClearPassword();
+  std::string sanitized_context_url =
+      context_url_.ReplaceComponents(replacements).spec();
+  std::string sanitized_other_url =
+      other_url.ReplaceComponents(replacements).spec();
+  base::DictionaryValue body;
+  body.SetString(kDisposition,
+                 is_report_only ? kDispositionReporting : kDispositionEnforce);
+  body.SetString(kDocumentURI, sanitized_context_url);
+  body.SetString(kNavigationURI, sanitized_other_url);
+  body.SetString(kViolationType, is_reported_from_document
+                                     ? kViolationTypeFromDocument
+                                     : kViolationTypeToDocument);
+  body.SetString(
+      kEffectivePolicy,
+      CoopValueToString(is_report_only ? coop_.report_only_value : coop_.value,
+                        coep_.value, coep_.report_only_value));
+  storage_partition_->GetNetworkContext()->QueueReport(
+      "coop", *endpoint, context_url_, /*user_agent=*/base::nullopt,
+      std::move(body));
+}
+
+void CrossOriginOpenerPolicyReporter::Clone(
+    mojo::PendingReceiver<network::mojom::CrossOriginOpenerPolicyReporter>
+        receiver) {
+  receiver_set_.Add(this, std::move(receiver));
+}
+
+GURL CrossOriginOpenerPolicyReporter::GetPreviousDocumentUrlForReporting(
+    const std::vector<GURL>& redirect_chain,
+    const GURL& referrer_url) {
+  // If the current document and all its redirect chain are same-origin with
+  // the previous document, this is the previous document URL.
+  auto source_origin = url::Origin::Create(source_url_);
+  bool is_redirect_chain_same_origin = true;
+  for (auto& redirect_url : redirect_chain) {
+    auto redirect_origin = url::Origin::Create(redirect_url);
+    if (!redirect_origin.IsSameOriginWith(source_origin)) {
+      is_redirect_chain_same_origin = false;
+      break;
+    }
+  }
+  if (is_redirect_chain_same_origin)
+    return source_url_;
+
+  // Otherwise, it's the referrer of the navigation.
+  return referrer_url;
+}
+
+GURL CrossOriginOpenerPolicyReporter::GetNextDocumentUrlForReporting(
+    const std::vector<GURL>& redirect_chain,
+    const GlobalFrameRoutingId& initiator_routing_id) {
+  const url::Origin& source_origin = url::Origin::Create(source_url_);
+
+  // If the next document and all its redirect chain are same-origin with the
+  // current document, this is the next document URL.
+  bool is_redirect_chain_same_origin = true;
+  for (auto& redirect_url : redirect_chain) {
+    auto redirect_origin = url::Origin::Create(redirect_url);
+    if (!redirect_origin.IsSameOriginWith(source_origin)) {
+      is_redirect_chain_same_origin = false;
+      break;
+    }
+  }
+  if (is_redirect_chain_same_origin)
+    return redirect_chain[redirect_chain.size() - 1];
+
+  // If the current document is the initiator of the navigation, then it's the
+  // initial navigation URL.
+  if ((source_routing_id_.frame_routing_id ==
+       initiator_routing_id.frame_routing_id) &&
+      (source_routing_id_.child_id == initiator_routing_id.child_id)) {
+    return redirect_chain[0];
+  }
+
+  // Otherwise, it's the empty URL.
+  return GURL();
+}
+
+}  // namespace content
diff --git a/content/browser/net/cross_origin_opener_policy_reporter.h b/content/browser/net/cross_origin_opener_policy_reporter.h
new file mode 100644
index 0000000..db91781
--- /dev/null
+++ b/content/browser/net/cross_origin_opener_policy_reporter.h
@@ -0,0 +1,95 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_NET_CROSS_ORIGIN_OPENER_POLICY_REPORTER_H_
+#define CONTENT_BROWSER_NET_CROSS_ORIGIN_OPENER_POLICY_REPORTER_H_
+
+#include <string>
+
+#include "base/optional.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/global_routing_id.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "services/network/public/mojom/cross_origin_embedder_policy.mojom.h"
+#include "services/network/public/mojom/cross_origin_opener_policy.mojom.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class StoragePartition;
+class RenderFrameHostImpl;
+
+// Used to report (potential) COOP breakages.
+// A CrossOriginOpenerPolicyReporter lives in the browser process and is either
+// held by the NavigationRequest during navigation or by the RenderFrameHostImpl
+// after the document has committed.
+// To make calls from other processes, create a mojo endpoint using Clone and
+// pass the receiver to other processes.
+// Any functions other than the destructor must not be called after the
+// associated StoragePartition is destructed.
+class CONTENT_EXPORT CrossOriginOpenerPolicyReporter final
+    : public network::mojom::CrossOriginOpenerPolicyReporter {
+ public:
+  CrossOriginOpenerPolicyReporter(
+      StoragePartition* storage_partition,
+      RenderFrameHostImpl* current_frame_host,
+      const GURL& context_url,
+      const network::CrossOriginOpenerPolicy& coop,
+      const network::CrossOriginEmbedderPolicy& coep);
+  ~CrossOriginOpenerPolicyReporter() override;
+  CrossOriginOpenerPolicyReporter(const CrossOriginOpenerPolicyReporter&) =
+      delete;
+  CrossOriginOpenerPolicyReporter& operator=(
+      const CrossOriginOpenerPolicyReporter&) = delete;
+
+  // network::mojom::CrossOriginOpenerPolicyReporter implementation.
+  void QueueOpenerBreakageReport(const GURL& other_url,
+                                 bool is_reported_from_document,
+                                 bool is_report_only) override;
+
+  // Returns the "previous" URL that is safe to expose.
+  // Reference, "Next document URL for reporting" section:
+  // https://github.com/camillelamy/explainers/blob/master/coop_reporting.md#safe-urls-for-reporting
+  GURL GetPreviousDocumentUrlForReporting(
+      const std::vector<GURL>& redirect_chain,
+      const GURL& referrer_url);
+
+  // Returns the "next" URL that is safe to expose.
+  // Reference, "Next document URL for reporting" section:
+  // https://github.com/camillelamy/explainers/blob/master/coop_reporting.md#safe-urls-for-reporting
+  GURL GetNextDocumentUrlForReporting(
+      const std::vector<GURL>& redirect_chain,
+      const GlobalFrameRoutingId& initiator_routing_id);
+
+  void Clone(
+      mojo::PendingReceiver<network::mojom::CrossOriginOpenerPolicyReporter>
+          receiver) override;
+
+ private:
+  friend class CrossOriginOpenerPolicyReporterTest;
+
+  // Used in unit_tests that do not have access to a RenderFrameHost.
+  CrossOriginOpenerPolicyReporter(
+      StoragePartition* storage_partition,
+      const GURL& source_url,
+      const GlobalFrameRoutingId source_routing_id,
+      const GURL& context_url,
+      const network::CrossOriginOpenerPolicy& coop,
+      const network::CrossOriginEmbedderPolicy& coep);
+
+  // See the class comment.
+  StoragePartition* const storage_partition_;
+  GURL source_url_;
+  GlobalFrameRoutingId source_routing_id_;
+  const GURL context_url_;
+  network::CrossOriginOpenerPolicy coop_;
+  network::CrossOriginEmbedderPolicy coep_;
+
+  mojo::ReceiverSet<network::mojom::CrossOriginOpenerPolicyReporter>
+      receiver_set_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_NET_CROSS_ORIGIN_OPENER_POLICY_REPORTER_H_
diff --git a/content/browser/net/cross_origin_opener_policy_reporter_unittest.cc b/content/browser/net/cross_origin_opener_policy_reporter_unittest.cc
new file mode 100644
index 0000000..b4e9bb3
--- /dev/null
+++ b/content/browser/net/cross_origin_opener_policy_reporter_unittest.cc
@@ -0,0 +1,159 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/net/cross_origin_opener_policy_reporter.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/test/task_environment.h"
+#include "base/values.h"
+#include "content/public/test/test_storage_partition.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "services/network/test/test_network_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+
+class TestNetworkContext : public network::TestNetworkContext {
+ public:
+  struct Report {
+    Report(const std::string& type,
+           const std::string& group,
+           const GURL& url,
+           base::Value body)
+        : type(type), group(group), url(url), body(std::move(body)) {}
+
+    std::string type;
+    std::string group;
+    GURL url;
+    base::Value body;
+  };
+  void QueueReport(const std::string& type,
+                   const std::string& group,
+                   const GURL& url,
+                   const base::Optional<std::string>& user_agent,
+                   base::Value body) override {
+    DCHECK(!user_agent);
+    reports_.emplace_back(Report(type, group, url, std::move(body)));
+  }
+
+  const std::vector<Report>& reports() const { return reports_; }
+
+ private:
+  std::vector<Report> reports_;
+};
+
+}  // namespace
+
+class CrossOriginOpenerPolicyReporterTest : public testing::Test {
+ public:
+  using Report = TestNetworkContext::Report;
+  CrossOriginOpenerPolicyReporterTest() {
+    storage_partition_.set_network_context(&network_context_);
+    coop_.value = network::mojom::CrossOriginOpenerPolicyValue::kSameOrigin;
+    coep_.value = network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
+    coop_.reporting_endpoint = "e1";
+    context_url_ = GURL("https://www1.example.com/x");
+  }
+
+  StoragePartition* storage_partition() { return &storage_partition_; }
+  const TestNetworkContext& network_context() const { return network_context_; }
+  const GURL& context_url() const { return context_url_; }
+  const network::CrossOriginOpenerPolicy& coop() const { return coop_; }
+  const network::CrossOriginEmbedderPolicy& coep() const { return coep_; }
+
+ protected:
+  std::unique_ptr<CrossOriginOpenerPolicyReporter> GetReporter() {
+    return std::unique_ptr<CrossOriginOpenerPolicyReporter>(
+        new CrossOriginOpenerPolicyReporter(storage_partition(), GURL(),
+                                            GlobalFrameRoutingId(123, 456),
+                                            context_url(), coop(), coep()));
+  }
+
+ private:
+  base::test::TaskEnvironment task_environment_;
+  TestNetworkContext network_context_;
+  TestStoragePartition storage_partition_;
+  GURL context_url_;
+  network::CrossOriginOpenerPolicy coop_;
+  network::CrossOriginEmbedderPolicy coep_;
+};
+
+TEST_F(CrossOriginOpenerPolicyReporterTest, Basic) {
+  auto reporter = GetReporter();
+
+  reporter->QueueOpenerBreakageReport(
+      GURL("https://www1.example.com/y#foo?bar=baz"), false, false);
+  reporter->QueueOpenerBreakageReport(GURL("http://www2.example.com:41/z"),
+                                      true, false);
+
+  ASSERT_EQ(2u, network_context().reports().size());
+  const Report& r1 = network_context().reports()[0];
+  const Report& r2 = network_context().reports()[1];
+
+  EXPECT_EQ(r1.type, "coop");
+  EXPECT_EQ(r1.body.FindKey("disposition")->GetString(), "enforce");
+  EXPECT_EQ(r1.body.FindKey("document-uri")->GetString(), context_url());
+  EXPECT_EQ(r1.body.FindKey("navigation-uri")->GetString(),
+            "https://www1.example.com/y#foo?bar=baz");
+  EXPECT_EQ(r1.body.FindKey("violation-type")->GetString(),
+            "navigation-to-document");
+  EXPECT_EQ(r1.body.FindKey("effective-policy")->GetString(),
+            "same-origin-plus-coep");
+
+  EXPECT_EQ(r2.type, "coop");
+  EXPECT_EQ(r2.body.FindKey("disposition")->GetString(), "enforce");
+  EXPECT_EQ(r2.body.FindKey("document-uri")->GetString(), context_url());
+  EXPECT_EQ(r2.body.FindKey("navigation-uri")->GetString(),
+            "http://www2.example.com:41/z");
+  EXPECT_EQ(r2.body.FindKey("violation-type")->GetString(),
+            "navigation-from-document");
+  EXPECT_EQ(r2.body.FindKey("effective-policy")->GetString(),
+            "same-origin-plus-coep");
+}
+
+TEST_F(CrossOriginOpenerPolicyReporterTest, UserAndPassSanitization) {
+  auto reporter = GetReporter();
+
+  reporter->QueueOpenerBreakageReport(GURL("https://u:p@www2.example.com/x"),
+                                      false, false);
+
+  ASSERT_EQ(1u, network_context().reports().size());
+  const Report& r1 = network_context().reports()[0];
+
+  EXPECT_EQ(r1.type, "coop");
+  EXPECT_EQ(r1.body.FindKey("document-uri")->GetString(),
+            "https://www1.example.com/x");
+  EXPECT_EQ(r1.body.FindKey("navigation-uri")->GetString(),
+            "https://www2.example.com/x");
+}
+
+TEST_F(CrossOriginOpenerPolicyReporterTest, Clone) {
+  auto reporter = GetReporter();
+
+  mojo::Remote<network::mojom::CrossOriginOpenerPolicyReporter> remote;
+  reporter->Clone(remote.BindNewPipeAndPassReceiver());
+
+  remote->QueueOpenerBreakageReport(GURL("https://www1.example.com/y"), false,
+                                    false);
+
+  remote.FlushForTesting();
+
+  ASSERT_EQ(1u, network_context().reports().size());
+  const Report& r1 = network_context().reports()[0];
+
+  EXPECT_EQ(r1.type, "coop");
+  EXPECT_EQ(r1.body.FindKey("disposition")->GetString(), "enforce");
+  EXPECT_EQ(r1.body.FindKey("document-uri")->GetString(), context_url());
+  EXPECT_EQ(r1.body.FindKey("navigation-uri")->GetString(),
+            "https://www1.example.com/y");
+  EXPECT_EQ(r1.body.FindKey("violation-type")->GetString(),
+            "navigation-to-document");
+  EXPECT_EQ(r1.body.FindKey("effective-policy")->GetString(),
+            "same-origin-plus-coep");
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/input/touch_action_browsertest.cc b/content/browser/renderer_host/input/touch_action_browsertest.cc
index 4c0d99b..b56634b2 100644
--- a/content/browser/renderer_host/input/touch_action_browsertest.cc
+++ b/content/browser/renderer_host/input/touch_action_browsertest.cc
@@ -346,11 +346,10 @@
                 { "name": "pointerUp"}]}]
         )HTML";
 
-    base::JSONReader json_reader;
-    base::Optional<base::Value> params =
-        json_reader.ReadToValue(pointer_actions_json);
-    ASSERT_TRUE(params.has_value()) << json_reader.GetErrorMessage();
-    ActionsParser actions_parser(std::move(params.value()));
+    base::JSONReader::ValueWithError parsed_json =
+        base::JSONReader::ReadAndReturnValueWithError(pointer_actions_json);
+    ASSERT_TRUE(parsed_json.value) << parsed_json.error_message;
+    ActionsParser actions_parser(std::move(*parsed_json.value));
 
     ASSERT_TRUE(actions_parser.ParsePointerActionSequence());
 
@@ -385,11 +384,10 @@
         }]
         )HTML";
 
-    base::JSONReader json_reader;
-    base::Optional<base::Value> params =
-        json_reader.ReadToValue(pointer_actions_json);
-    ASSERT_TRUE(params.has_value()) << json_reader.GetErrorMessage();
-    ActionsParser actions_parser(std::move(params.value()));
+    base::JSONReader::ValueWithError parsed_json =
+        base::JSONReader::ReadAndReturnValueWithError(pointer_actions_json);
+    ASSERT_TRUE(parsed_json.value) << parsed_json.error_message;
+    ActionsParser actions_parser(std::move(*parsed_json.value));
 
     ASSERT_TRUE(actions_parser.ParsePointerActionSequence());
 
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 3a2c9424..0d288ae 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -1334,8 +1334,6 @@
 
   // Actual audio parameters are required only for
   // MEDIA_GUM_TAB_AUDIO_CAPTURE.
-  // TODO(guidou): MEDIA_GUM_TAB_AUDIO_CAPTURE should not be a special
-  // case. See https://crbug.com/584287.
   if (request->audio_type() == MediaStreamType::GUM_TAB_AUDIO_CAPTURE) {
     // Using base::Unretained is safe: |audio_system_| will post
     // PostRequestToUI() to IO thread, and MediaStreamManager is deleted on the
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index 15721aa..a56cb7c 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -45,6 +45,7 @@
 #include "content/public/common/content_features.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "net/base/url_util.h"
+#include "storage/browser/quota/quota_client_type.h"
 #include "storage/browser/quota/quota_manager_proxy.h"
 #include "storage/browser/quota/special_storage_policy.h"
 #include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
@@ -1534,7 +1535,8 @@
 
   if (quota_manager_proxy) {
     quota_manager_proxy->RegisterClient(
-        base::MakeRefCounted<ServiceWorkerQuotaClient>(this));
+        base::MakeRefCounted<ServiceWorkerQuotaClient>(this),
+        storage::QuotaClientType::kServiceWorker);
   }
 
   context_core_ = std::make_unique<ServiceWorkerContextCore>(
diff --git a/content/browser/service_worker/service_worker_quota_client.cc b/content/browser/service_worker/service_worker_quota_client.cc
index 7cb9b81..4af38cb 100644
--- a/content/browser/service_worker/service_worker_quota_client.cc
+++ b/content/browser/service_worker/service_worker_quota_client.cc
@@ -53,10 +53,6 @@
 ServiceWorkerQuotaClient::~ServiceWorkerQuotaClient() {
 }
 
-storage::QuotaClientType ServiceWorkerQuotaClient::type() const {
-  return storage::QuotaClientType::kServiceWorker;
-}
-
 void ServiceWorkerQuotaClient::GetOriginUsage(const url::Origin& origin,
                                               StorageType type,
                                               GetUsageCallback callback) {
diff --git a/content/browser/service_worker/service_worker_quota_client.h b/content/browser/service_worker/service_worker_quota_client.h
index 3e4d51c..23d6de0f 100644
--- a/content/browser/service_worker/service_worker_quota_client.h
+++ b/content/browser/service_worker/service_worker_quota_client.h
@@ -22,7 +22,6 @@
       ServiceWorkerContextWrapper* context);
 
   // QuotaClient method overrides
-  storage::QuotaClientType type() const override;
   void OnQuotaManagerDestroyed() override {}
   void GetOriginUsage(const url::Origin& origin,
                       blink::mojom::StorageType type,
@@ -39,6 +38,9 @@
                              base::OnceClosure callback) override;
   bool DoesSupport(blink::mojom::StorageType type) const override;
 
+  static constexpr storage::QuotaClientType kType =
+      storage::QuotaClientType::kServiceWorker;
+
  private:
   friend class ServiceWorkerContextWrapper;
   friend class ServiceWorkerQuotaClientTest;
diff --git a/content/browser/url_loader_factory_params_helper.cc b/content/browser/url_loader_factory_params_helper.cc
index 8315b1f..dd12e90 100644
--- a/content/browser/url_loader_factory_params_helper.cc
+++ b/content/browser/url_loader_factory_params_helper.cc
@@ -42,7 +42,6 @@
     RenderProcessHost* process,
     const url::Origin& origin,
     const base::Optional<url::Origin>& request_initiator_site_lock,
-    const base::Optional<url::Origin>& top_frame_origin,
     bool is_trusted,
     const base::Optional<base::UnguessableToken>& top_frame_token,
     const net::IsolationInfo& isolation_info,
@@ -65,7 +64,6 @@
 
   params->process_id = process->GetID();
   params->request_initiator_site_lock = request_initiator_site_lock;
-  params->top_frame_origin = top_frame_origin;
 
   params->is_trusted = is_trusted;
   params->top_frame_id = top_frame_token;
@@ -117,8 +115,6 @@
       process,
       frame_origin,  // origin
       frame_origin,  // request_initiator_site_lock
-      // top_frame_origin
-      frame->ComputeTopFrameOrigin(frame_origin),
       false,  // is_trusted
       frame->GetTopFrameToken(), frame->GetIsolationInfoForSubresources(),
       std::move(client_security_state), std::move(coep_reporter),
@@ -141,7 +137,6 @@
       frame->GetProcess(),
       isolated_world_origin,  // origin
       main_world_origin,      // request_initiator_site_lock
-      base::nullopt,          // top_frame_origin
       false,                  // is_trusted
       frame->GetTopFrameToken(), frame->GetIsolationInfoForSubresources(),
       std::move(client_security_state),
@@ -164,8 +159,6 @@
   return CreateParams(frame->GetProcess(),
                       frame_origin,  // origin
                       frame_origin,  // request_initiator_site_lock
-                      // top_frame_origin
-                      frame->ComputeTopFrameOrigin(frame_origin),
                       true,  // is_trusted
                       frame->GetTopFrameToken(),
                       net::IsolationInfo(),  // isolation_info
@@ -191,7 +184,6 @@
       process,
       request_initiator,  // origin
       request_initiator,  // request_initiator_site_lock
-      base::nullopt,      // top_frame_origin
       false,              // is_trusted
       base::nullopt,      // top_frame_token
       isolation_info,
@@ -234,7 +226,6 @@
       process,
       url::Origin(),                // origin
       request_initiator_site_lock,  // request_initiator_site_lock
-      base::nullopt,                // top_frame_origin
       false,                        // is_trusted
       top_frame_token, isolation_info,
       nullptr,             // client_security_state
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 1c436a8..3e55f2ee 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3410,6 +3410,13 @@
 }
 
 device::mojom::GeolocationContext* WebContentsImpl::GetGeolocationContext() {
+  if (delegate_) {
+    auto* installed_webapp_context =
+        delegate_->GetInstalledWebappGeolocationContext();
+    if (installed_webapp_context)
+      return installed_webapp_context;
+  }
+
   if (!geolocation_context_) {
     GetDeviceService().BindGeolocationContext(
         geolocation_context_.BindNewPipeAndPassReceiver());
@@ -4796,15 +4803,22 @@
 
 void WebContentsImpl::OnDidRunContentWithCertificateErrors(
     RenderFrameHostImpl* source) {
-  // TODO(nick, estark): Do we need to consider |source| here somehow?
-  NavigationEntry* entry = controller_.GetVisibleEntry();
-  if (!entry)
+  // For RenderFrameHosts that are inactive and going to be discarded, we can
+  // disregard this message; there's no need to update the UI if the UI will
+  // never be shown again.
+  //
+  // We still process this message for speculative RenderFrameHosts. This can
+  // happen when a subframe's main resource has a certificate error. The
+  // currently committed navigation entry will get marked as having run insecure
+  // content and that will carry over to the navigation entry for the
+  // speculative RFH when it commits.
+  if (source->lifecycle_state() !=
+          RenderFrameHostImpl::LifecycleState::kSpeculative &&
+      source->IsInactiveAndDisallowReactivation()) {
     return;
-
-  // TODO(estark): check that this does something reasonable for
-  // about:blank and sandboxed origins. https://crbug.com/609527
+  }
   controller_.ssl_manager()->DidRunContentWithCertErrors(
-      entry->GetURL().GetOrigin());
+      source->GetMainFrame()->GetLastCommittedOrigin().GetURL());
 }
 
 void WebContentsImpl::DOMContentLoaded(RenderFrameHost* render_frame_host) {
diff --git a/content/browser/webui/web_ui_security_browsertest.cc b/content/browser/webui/web_ui_security_browsertest.cc
index e2cb26d..1241cb88 100644
--- a/content/browser/webui/web_ui_security_browsertest.cc
+++ b/content/browser/webui/web_ui_security_browsertest.cc
@@ -7,6 +7,7 @@
 #include "base/hash/hash.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/path_service.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_restrictions.h"
@@ -17,12 +18,14 @@
 #include "content/browser/webui/web_ui_controller_factory_registry.h"
 #include "content/common/content_navigation_policy.h"
 #include "content/public/browser/site_isolation_policy.h"
+#include "content/public/browser/url_data_source.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_controller.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "content/public/common/bindings_policy.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_paths.h"
+#include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
@@ -457,81 +460,6 @@
   EXPECT_EQ(0, root->current_frame_host()->GetEnabledBindings());
 }
 
-// Verify fetch request to chrome-untrusted:// is blocked.
-IN_PROC_BROWSER_TEST_F(WebUISecurityTest,
-                       DisallowFetchRequestToChromeUntrusted) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL web_url(embedded_test_server()->GetURL("/title2.html"));
-  AddUntrustedDataSource(shell()->web_contents()->GetBrowserContext(),
-                         "test-host");
-
-  EXPECT_TRUE(NavigateToURL(shell(), web_url));
-  EXPECT_EQ(web_url, shell()->web_contents()->GetLastCommittedURL());
-
-  const char kFetchRequestScript[] =
-      "(async () => {"
-      "  try {"
-      "    let response = await fetch($1); "
-      "  }"
-      "  catch (e) {"
-      "    return e.message;"
-      "  }"
-      "  throw 'Fetch should fail';"
-      "})();";
-  {
-    GURL untrusted_url(GetChromeUntrustedUIURL("test-host/script.js"));
-    WebContentsConsoleObserver console_observer(shell()->web_contents());
-    console_observer.SetPattern(
-        "Fetch API cannot load " + untrusted_url.spec() +
-        ". URL scheme must be \"http\" or \"https\" for CORS request.");
-
-    EXPECT_EQ("Failed to fetch",
-              EvalJs(shell(), JsReplace(kFetchRequestScript, untrusted_url),
-                     EXECUTE_SCRIPT_DEFAULT_OPTIONS, 1 /* world_id */));
-    console_observer.Wait();
-  }
-}
-
-// Verify XHR request to chrome-untrusted:// is blocked.
-IN_PROC_BROWSER_TEST_F(WebUISecurityTest, DisallowXHRRequestToChromeUntrusted) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL web_url(embedded_test_server()->GetURL("/title2.html"));
-  AddUntrustedDataSource(shell()->web_contents()->GetBrowserContext(),
-                         "test-host");
-
-  EXPECT_TRUE(NavigateToURL(shell(), web_url));
-  EXPECT_EQ(web_url, shell()->web_contents()->GetLastCommittedURL());
-
-  const char kXHRRequest[] =
-      "new Promise((resolve) => {"
-      "  const xhttp = new XMLHttpRequest();"
-      "  xhttp.open('GET', $1, true);"
-      "  xhttp.onload = () => { "
-      "    resolve('Request should have failed');"
-      "  };"
-      "  xhttp.onerror = () => {"
-      "    resolve('Request failed');"
-      "  };"
-      "  xhttp.send();"
-      "}); ";
-  {
-    GURL untrusted_url(GetChromeUntrustedUIURL("test-host/script.js"));
-    const std::string host = web_url.GetOrigin().spec();
-
-    WebContentsConsoleObserver console_observer(shell()->web_contents());
-    console_observer.SetPattern(
-        "Access to XMLHttpRequest at '" + untrusted_url.spec() +
-        "' from origin '" + host.substr(0, host.length() - 1) +
-        "' has been blocked by CORS policy: Cross origin requests are only "
-        "supported for protocol schemes: http, data, chrome, https.");
-
-    EXPECT_EQ("Request failed",
-              EvalJs(shell(), JsReplace(kXHRRequest, untrusted_url),
-                     EXECUTE_SCRIPT_DEFAULT_OPTIONS, 1 /* world_id */));
-    console_observer.Wait();
-  }
-}
-
 // Verify load script from chrome-untrusted:// is blocked.
 IN_PROC_BROWSER_TEST_F(WebUISecurityTest,
                        DisallowResourceRequestToChromeUntrusted) {
@@ -647,4 +575,366 @@
   }
 }
 
+namespace {
+enum FetchMode { SAME_ORIGIN, CORS, NO_CORS };
+
+EvalJsResult PerformFetch(Shell* shell,
+                          const GURL& fetch_url,
+                          FetchMode fetch_mode = FetchMode::CORS) {
+  std::string fetch_mode_string;
+  switch (fetch_mode) {
+    case SAME_ORIGIN:
+      fetch_mode_string = "same-origin";
+      break;
+    case CORS:
+      fetch_mode_string = "cors";
+      break;
+    case NO_CORS:
+      fetch_mode_string = "no-cors";
+      break;
+    default:
+      NOTREACHED();
+  }
+  const char kFetchRequestScript[] =
+      "fetch($1, {mode: $2}).then("
+      "  response => 'success',"
+      "  error => error.message"
+      ");";
+
+  return EvalJs(shell,
+                JsReplace(kFetchRequestScript, fetch_url, fetch_mode_string),
+                EXECUTE_SCRIPT_DEFAULT_OPTIONS, 1 /* world_id */);
+}
+}  // namespace
+
+// Verify fetch request from web pages to chrome-untrusted:// is blocked,
+// because web pages don't have WebUIURLLoaderFactory for chrome-untrusted://
+// scheme.
+IN_PROC_BROWSER_TEST_F(WebUISecurityTest,
+                       DisallowWebPageFetchRequestToChromeUntrusted) {
+  const GURL untrusted_url = GURL("chrome-untrusted://test/title1.html");
+  AddUntrustedDataSource(shell()->web_contents()->GetBrowserContext(),
+                         untrusted_url.host());
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  const GURL web_url = embedded_test_server()->GetURL("/title2.html");
+  EXPECT_TRUE(NavigateToURL(shell(), web_url));
+
+  {
+    WebContentsConsoleObserver console_observer(shell()->web_contents());
+    EXPECT_EQ("Failed to fetch",
+              PerformFetch(shell(), untrusted_url, FetchMode::CORS));
+    console_observer.Wait();
+    EXPECT_EQ(console_observer.GetMessageAt(0),
+              base::StringPrintf("Fetch API cannot load %s. URL scheme must be "
+                                 "\"http\" or \"https\" for CORS request.",
+                                 untrusted_url.spec().c_str()));
+  }
+
+  {
+    WebContentsConsoleObserver console_observer(shell()->web_contents());
+    EXPECT_EQ("Failed to fetch",
+              PerformFetch(shell(), untrusted_url, FetchMode::NO_CORS));
+    console_observer.Wait();
+    EXPECT_EQ(console_observer.GetMessageAt(0),
+              base::StringPrintf("Fetch API cannot load %s. URL scheme "
+                                 "\"chrome-untrusted\" is not supported.",
+                                 untrusted_url.spec().c_str()));
+  }
+}
+
+// Verify a chrome-untrusted:// document can't fetch itself.
+IN_PROC_BROWSER_TEST_F(WebUISecurityTest, ChromeUntrustedFetchRequestToSelf) {
+  const GURL untrusted_url = GURL("chrome-untrusted://test/title1.html");
+  AddUntrustedDataSource(shell()->web_contents()->GetBrowserContext(),
+                         untrusted_url.host());
+
+  EXPECT_TRUE(NavigateToURL(shell(), untrusted_url));
+
+  WebContentsConsoleObserver console_observer(shell()->web_contents());
+  EXPECT_EQ("Failed to fetch",
+            PerformFetch(shell(), untrusted_url, FetchMode::SAME_ORIGIN));
+  console_observer.Wait();
+  EXPECT_EQ(console_observer.GetMessageAt(0),
+            base::StringPrintf("Fetch API cannot load %s. URL scheme "
+                               "\"chrome-untrusted\" is not supported.",
+                               untrusted_url.spec().c_str()));
+}
+
+// Verify cross-origin fetch request from a chrome-untrusted:// page to another
+// chrome-untrusted:// page is blocked by the default "default-src 'self'"
+// Content Security Policy on URLDataSource.
+IN_PROC_BROWSER_TEST_F(
+    WebUISecurityTest,
+    DisallowCrossOriginFetchRequestToChromeUntrustedByDefault) {
+  const GURL untrusted_url1 = GURL("chrome-untrusted://test1/title1.html");
+  AddUntrustedDataSource(shell()->web_contents()->GetBrowserContext(),
+                         untrusted_url1.host());
+  const GURL untrusted_url2 = GURL("chrome-untrusted://test2/title2.html");
+  AddUntrustedDataSource(shell()->web_contents()->GetBrowserContext(),
+                         untrusted_url2.host());
+
+  EXPECT_TRUE(NavigateToURL(shell(), untrusted_url1));
+
+  {
+    WebContentsConsoleObserver console_observer(shell()->web_contents());
+    EXPECT_EQ("Failed to fetch",
+              PerformFetch(shell(), untrusted_url2, FetchMode::CORS));
+    console_observer.Wait();
+    EXPECT_EQ(console_observer.GetMessageAt(0),
+              base::StringPrintf(
+                  "Refused to connect to '%s' because it violates the "
+                  "following Content Security Policy directive: \"default-src "
+                  "'self'\". Note that 'connect-src' was not explicitly set, "
+                  "so 'default-src' is used as a fallback.\n",
+                  untrusted_url2.spec().c_str()));
+  }
+
+  {
+    WebContentsConsoleObserver console_observer(shell()->web_contents());
+    EXPECT_EQ("Failed to fetch",
+              PerformFetch(shell(), untrusted_url2, FetchMode::NO_CORS));
+    console_observer.Wait();
+    EXPECT_EQ(console_observer.GetMessageAt(0),
+              base::StringPrintf(
+                  "Refused to connect to '%s' because it violates the "
+                  "following Content Security Policy directive: \"default-src "
+                  "'self'\". Note that 'connect-src' was not explicitly set, "
+                  "so 'default-src' is used as a fallback.\n",
+                  untrusted_url2.spec().c_str()));
+  }
+}
+
+// Verify cross-origin fetch request from a chrome-untrusted:// page to another
+// chrome-untrusted:// page fails because chrome-untrusted:// scheme does not
+// support Fetch API, even if CSP allows it.
+IN_PROC_BROWSER_TEST_F(WebUISecurityTest,
+                       CrossOriginFetchRequestToChromeUntrustedFails) {
+  TestUntrustedDataSourceCSP csp;
+  csp.default_src = "default-src chrome-untrusted://test2;";
+  const GURL untrusted_url1 = GURL("chrome-untrusted://test1/title1.html");
+  AddUntrustedDataSource(shell()->web_contents()->GetBrowserContext(),
+                         untrusted_url1.host(), csp);
+  const GURL untrusted_url2 = GURL("chrome-untrusted://test2/title2.html");
+  AddUntrustedDataSource(shell()->web_contents()->GetBrowserContext(),
+                         untrusted_url2.host());
+
+  EXPECT_TRUE(NavigateToURL(shell(), untrusted_url1));
+  {
+    WebContentsConsoleObserver console_observer(shell()->web_contents());
+    EXPECT_EQ("Failed to fetch",
+              PerformFetch(shell(), untrusted_url2, FetchMode::CORS));
+    console_observer.Wait();
+    EXPECT_EQ(console_observer.GetMessageAt(0),
+              base::StringPrintf("Fetch API cannot load %s. URL scheme must be "
+                                 "\"http\" or \"https\" for CORS request.",
+                                 untrusted_url2.spec().c_str()));
+  }
+
+  {
+    WebContentsConsoleObserver console_observer(shell()->web_contents());
+    EXPECT_EQ("Failed to fetch",
+              PerformFetch(shell(), untrusted_url2, FetchMode::NO_CORS));
+    console_observer.Wait();
+    EXPECT_EQ(console_observer.GetMessageAt(0),
+              base::StringPrintf("Fetch API cannot load %s. URL scheme "
+                                 "\"chrome-untrusted\" is not supported.",
+                                 untrusted_url2.spec().c_str()));
+  }
+}
+
+// Verify fetch request from a chrome-untrusted:// page to a chrome:// page
+// is blocked because chrome-untrusted:// pages don't have WebUIURLLoaderFactory
+// for chrome:// scheme, even if CSP allows this.
+IN_PROC_BROWSER_TEST_F(WebUISecurityTest,
+                       DisallowChromeUntrustedFetchRequestToChrome) {
+  TestUntrustedDataSourceCSP csp;
+  csp.default_src = "default-src chrome://webui;";
+  const GURL untrusted_url = GURL("chrome-untrusted://test1/title1.html");
+  AddUntrustedDataSource(shell()->web_contents()->GetBrowserContext(),
+                         untrusted_url.host(), csp);
+
+  const GURL chrome_url = GURL("chrome://webui/title2.html");
+
+  EXPECT_TRUE(NavigateToURL(shell(), untrusted_url));
+
+  {
+    WebContentsConsoleObserver console_observer(shell()->web_contents());
+    EXPECT_EQ("Failed to fetch",
+              PerformFetch(shell(), chrome_url, FetchMode::CORS));
+    console_observer.Wait();
+    EXPECT_EQ(console_observer.GetMessageAt(0),
+              base::StringPrintf("Fetch API cannot load %s. URL scheme must be "
+                                 "\"http\" or \"https\" for CORS request.",
+                                 chrome_url.spec().c_str()));
+  }
+
+  {
+    WebContentsConsoleObserver console_observer(shell()->web_contents());
+    EXPECT_EQ("Failed to fetch",
+              PerformFetch(shell(), chrome_url, FetchMode::NO_CORS));
+    console_observer.Wait();
+    EXPECT_EQ(
+        console_observer.GetMessageAt(0),
+        base::StringPrintf(
+            "Fetch API cannot load %s. URL scheme \"chrome\" is not supported.",
+            chrome_url.spec().c_str()));
+  }
+}
+
+namespace {
+class UntrustedSourceWithCorsSupport : public URLDataSource {
+ public:
+  static std::unique_ptr<UntrustedSourceWithCorsSupport> CreateForHost(
+      std::string host) {
+    std::string source_name = base::StrCat(
+        {kChromeUIUntrustedScheme, url::kStandardSchemeSeparator, host, "/"});
+    return std::make_unique<UntrustedSourceWithCorsSupport>(source_name);
+  }
+  explicit UntrustedSourceWithCorsSupport(std::string name) : name_(name) {}
+  UntrustedSourceWithCorsSupport& operator=(
+      const UntrustedSourceWithCorsSupport&) = delete;
+  UntrustedSourceWithCorsSupport(const UntrustedSourceWithCorsSupport&) =
+      delete;
+  ~UntrustedSourceWithCorsSupport() override = default;
+
+  // URLDataSource:
+  std::string GetSource() override { return name_; }
+  std::string GetAccessControlAllowOriginForOrigin(
+      const std::string& origin) override {
+    return origin;
+  }
+  std::string GetMimeType(const std::string& path) override {
+    return "text/html";
+  }
+  void StartDataRequest(const GURL& url,
+                        const WebContents::Getter& wc_getter,
+                        GotDataCallback callback) override {
+    std::string dummy_html = "<html><body>dummy</body></html>";
+    scoped_refptr<base::RefCountedString> response =
+        base::RefCountedString::TakeString(&dummy_html);
+    std::move(callback).Run(response.get());
+  }
+
+ private:
+  std::string name_;
+};
+
+EvalJsResult PerformXHRRequest(Shell* shell, const GURL& xhr_url) {
+  const char kXHRRequestScript[] =
+      "new Promise((resolve) => {"
+      "  const xhr = new XMLHttpRequest();"
+      "  xhr.open('GET', $1);"
+      "  xhr.onload = () => resolve('success');"
+      "  xhr.onerror = progress_event => resolve(progress_event.type);"
+      "  xhr.send();"
+      "}); ";
+
+  return EvalJs(shell, JsReplace(kXHRRequestScript, xhr_url),
+                EXECUTE_SCRIPT_DEFAULT_OPTIONS, 1 /* world_id */);
+}
+}  // namespace
+
+// Verify XHR request from web pages to chrome-untrusted:// is blocked, because
+// web pages don't have WebUIURLLoader required to load chrome-untrusted://
+// resources.
+IN_PROC_BROWSER_TEST_F(WebUISecurityTest,
+                       DisallowWebPageXHRRequestToChromeUntrusted) {
+  const GURL untrusted_url = GURL("chrome-untrusted://test/title1.html");
+  AddUntrustedDataSource(shell()->web_contents()->GetBrowserContext(),
+                         untrusted_url.host());
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const GURL web_url = embedded_test_server()->GetURL("/title2.html");
+
+  EXPECT_TRUE(NavigateToURL(shell(), web_url));
+
+  DevToolsInspectorLogWatcher log_watcher(shell()->web_contents());
+  EXPECT_EQ("error", PerformXHRRequest(shell(), untrusted_url));
+  log_watcher.FlushAndStopWatching();
+
+  EXPECT_EQ(log_watcher.last_message(),
+            "Failed to load resource: net::ERR_UNKNOWN_URL_SCHEME");
+}
+
+// Verify a chrome-untrusted:// document can XHR itself.
+IN_PROC_BROWSER_TEST_F(WebUISecurityTest,
+                       AllowChromeUntrustedXHRRequestToSelf) {
+  const GURL untrusted_url = GURL("chrome-untrusted://test/title1.html");
+  AddUntrustedDataSource(shell()->web_contents()->GetBrowserContext(),
+                         untrusted_url.host());
+
+  EXPECT_TRUE(NavigateToURL(shell(), untrusted_url));
+  EXPECT_EQ("success", PerformXHRRequest(shell(), untrusted_url));
+}
+
+// Verify cross-origin XHR request from a chrome-untrusted:// page to another
+// chrome-untrusted:// page is blocked by "default-src 'self';" Content Security
+// Policy.
+IN_PROC_BROWSER_TEST_F(
+    WebUISecurityTest,
+    DisallowCrossOriginXHRRequestToChromeUntrustedByDefault) {
+  const GURL untrusted_url1 = GURL("chrome-untrusted://test1/title1.html");
+  AddUntrustedDataSource(shell()->web_contents()->GetBrowserContext(),
+                         untrusted_url1.host());
+  const GURL untrusted_url2 = GURL("chrome-untrusted://test2/");
+  URLDataSource::Add(
+      shell()->web_contents()->GetBrowserContext(),
+      UntrustedSourceWithCorsSupport::CreateForHost(untrusted_url2.host()));
+
+  EXPECT_TRUE(NavigateToURL(shell(), untrusted_url1));
+
+  WebContentsConsoleObserver console_observer(shell()->web_contents());
+  EXPECT_EQ("error", PerformXHRRequest(shell(), untrusted_url2));
+  console_observer.Wait();
+  EXPECT_EQ(console_observer.GetMessageAt(0),
+            base::StringPrintf(
+                "Refused to connect to '%s' because it violates the "
+                "following Content Security Policy directive: \"default-src "
+                "'self'\". Note that 'connect-src' was not explicitly set, "
+                "so 'default-src' is used as a fallback.\n",
+                untrusted_url2.spec().c_str()));
+}
+
+// Verify cross-origin XHR request from a chrome-untrusted:// page to another
+// chrome-untrusted:// page is successful, if Content Security Policy allows it,
+// and the requested resource presents an Access-Control-Allow-Origin header.
+IN_PROC_BROWSER_TEST_F(
+    WebUISecurityTest,
+    CrossOriginXHRRequestToChromeUntrustedIfContenSecurityPolicyAllowsIt) {
+  TestUntrustedDataSourceCSP csp;
+  csp.default_src = "default-src chrome-untrusted://test2;";
+  const GURL untrusted_url1 = GURL("chrome-untrusted://test1/title1.html");
+  AddUntrustedDataSource(shell()->web_contents()->GetBrowserContext(),
+                         untrusted_url1.host(), csp);
+  const GURL untrusted_url2 = GURL("chrome-untrusted://test2/");
+  URLDataSource::Add(
+      shell()->web_contents()->GetBrowserContext(),
+      UntrustedSourceWithCorsSupport::CreateForHost(untrusted_url2.host()));
+
+  EXPECT_TRUE(NavigateToURL(shell(), untrusted_url1));
+  EXPECT_EQ("success", PerformXHRRequest(shell(), untrusted_url2));
+}
+
+// Verify XHR request from a chrome-untrusted:// page to a chrome:// page is
+// blocked, even if CSP allows this.
+IN_PROC_BROWSER_TEST_F(WebUISecurityTest,
+                       DisallowChromeUntrustedXHRRequestToChrome) {
+  TestUntrustedDataSourceCSP csp;
+  csp.default_src = "default-src chrome://webui;";
+  const GURL untrusted_url = GURL("chrome-untrusted://test1/title1.html");
+  AddUntrustedDataSource(shell()->web_contents()->GetBrowserContext(),
+                         untrusted_url.host(), csp);
+
+  const GURL chrome_url = GURL("chrome://webui/title2.html");
+
+  EXPECT_TRUE(NavigateToURL(shell(), untrusted_url));
+
+  WebContentsConsoleObserver console_observer(shell()->web_contents());
+  EXPECT_EQ("error", PerformXHRRequest(shell(), chrome_url));
+  console_observer.Wait();
+  EXPECT_EQ(console_observer.GetMessageAt(0),
+            base::StringPrintf("Not allowed to load local resource: %s",
+                               chrome_url.spec().c_str()));
+}
+
 }  // namespace content
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 5f795e5..2eafa7e1 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -212,10 +212,10 @@
     {wf::EnableWebXR, features::kWebXr, kUseFeatureState},
     {wf::EnableWebXRARModule, features::kWebXrArModule, kUseFeatureState},
     {wf::EnableWebXRHitTest, features::kWebXrHitTest, kUseFeatureState},
-    {wf::EnableWebXRIncubations, features::kWebXrIncubations, kEnableOnly},
     {wf::EnableWebXRAnchors, features::kWebXrIncubations, kEnableOnly},
-    {wf::EnableWebXRLightEstimation, features::kWebXrIncubations, kEnableOnly},
     {wf::EnableWebXRCameraAccess, features::kWebXrIncubations, kEnableOnly},
+    {wf::EnableWebXRLightEstimation, features::kWebXrIncubations, kEnableOnly},
+    {wf::EnableWebXRPlaneDetection, features::kWebXrIncubations, kEnableOnly},
     {wf::EnableUserActivationPostMessageTransfer,
      features::kUserActivationPostMessageTransfer, kUseFeatureState},
     {wf::EnableUserActivationSameOriginVisibility,
diff --git a/content/common/url_schemes.cc b/content/common/url_schemes.cc
index c00901a2..dc37f12 100644
--- a/content/common/url_schemes.cc
+++ b/content/common/url_schemes.cc
@@ -84,6 +84,7 @@
     url::AddNoAccessScheme(scheme.c_str());
 
   schemes.cors_enabled_schemes.push_back(kChromeUIScheme);
+  schemes.cors_enabled_schemes.push_back(kChromeUIUntrustedScheme);
   for (auto& scheme : schemes.cors_enabled_schemes)
     url::AddCorsEnabledScheme(scheme.c_str());
 
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
index 6017278..50936cd 100644
--- a/content/public/browser/web_contents_delegate.cc
+++ b/content/public/browser/web_contents_delegate.cc
@@ -353,6 +353,11 @@
   return web_contents;
 }
 
+device::mojom::GeolocationContext*
+WebContentsDelegate::GetInstalledWebappGeolocationContext() {
+  return nullptr;
+}
+
 base::WeakPtr<WebContentsDelegate> WebContentsDelegate::GetDelegateWeakPtr() {
   return nullptr;
 }
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
index 3844c78..e545ff7 100644
--- a/content/public/browser/web_contents_delegate.h
+++ b/content/public/browser/web_contents_delegate.h
@@ -73,6 +73,12 @@
 struct SecurityStyleExplanations;
 }  // namespace content
 
+namespace device {
+namespace mojom {
+class GeolocationContext;
+}
+}  // namespace device
+
 namespace gfx {
 class Rect;
 class Size;
@@ -729,6 +735,12 @@
   // Invoked when media playback is interrupted or completed.
   virtual void MediaWatchTimeChanged(const MediaPlayerWatchTime& watch_time) {}
 
+  // Returns a  InstalledWebappGeolocationContext if this web content is running
+  // in a installed webapp and geolocation should be deleagted from the
+  // installed webapp; otherwise returns nullptr.
+  virtual device::mojom::GeolocationContext*
+  GetInstalledWebappGeolocationContext();
+
   // Returns a weak ptr to the web contents delegate.
   virtual base::WeakPtr<WebContentsDelegate> GetDelegateWeakPtr();
 
diff --git a/content/public/common/performance_manager/OWNERS b/content/public/common/performance_manager/OWNERS
index 08850f4..7e4c8d7 100644
--- a/content/public/common/performance_manager/OWNERS
+++ b/content/public/common/performance_manager/OWNERS
@@ -1,2 +1,5 @@
+file://components/performance_manager/OWNERS
+
+# For IPC security review
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/content/public/test/test_utils.cc b/content/public/test/test_utils.cc
index 9df229cf..aa31e5e 100644
--- a/content/public/test/test_utils.cc
+++ b/content/public/test/test_utils.cc
@@ -216,6 +216,10 @@
   return IsProactivelySwapBrowsingInstanceOnSameSiteNavigationEnabled();
 }
 
+bool CanSameSiteMainFrameNavigationsChangeSiteInstances() {
+  return IsProactivelySwapBrowsingInstanceOnSameSiteNavigationEnabled();
+}
+
 GURL GetWebUIURL(const std::string& host) {
   return GURL(GetWebUIURLString(host));
 }
diff --git a/content/public/test/test_utils.h b/content/public/test/test_utils.h
index d2486f1a5..62241588 100644
--- a/content/public/test/test_utils.h
+++ b/content/public/test/test_utils.h
@@ -105,6 +105,13 @@
 // is enabled on same-site main frame navigations.
 bool CanSameSiteMainFrameNavigationsChangeRenderFrameHosts();
 
+// Whether same-site navigations might result in a change of SiteInstances -
+// this will happen when ProactivelySwapBrowsingInstance is enabled on
+// same-site main frame navigations.
+// Note that unlike CanSameSiteMainFrameNavigationsChangeRenderFrameHosts()
+// above, this will not be true when RenderDocument for main-frame is enabled.
+bool CanSameSiteMainFrameNavigationsChangeSiteInstances();
+
 // Returns a GURL constructed from the WebUI scheme and the given host.
 GURL GetWebUIURL(const std::string& host);
 
diff --git a/content/public/test/web_ui_browsertest_util.cc b/content/public/test/web_ui_browsertest_util.cc
index a5d2efa3..05e5dce 100644
--- a/content/public/test/web_ui_browsertest_util.cc
+++ b/content/public/test/web_ui_browsertest_util.cc
@@ -116,6 +116,10 @@
       untrusted_data_source->OverrideContentSecurityPolicyScriptSrc(
           csp->script_src.value());
     }
+    if (csp->default_src.has_value()) {
+      untrusted_data_source->OverrideContentSecurityPolicyDefaultSrc(
+          csp->default_src.value());
+    }
     if (csp->no_xfo)
       untrusted_data_source->DisableDenyXFrameOptions();
     if (csp->frame_ancestors.has_value()) {
diff --git a/content/public/test/web_ui_browsertest_util.h b/content/public/test/web_ui_browsertest_util.h
index fb95886dd..286d3af 100644
--- a/content/public/test/web_ui_browsertest_util.h
+++ b/content/public/test/web_ui_browsertest_util.h
@@ -21,6 +21,7 @@
 
   base::Optional<std::string> child_src = base::nullopt;
   base::Optional<std::string> script_src = base::nullopt;
+  base::Optional<std::string> default_src = base::nullopt;
   bool no_xfo = false;
   base::Optional<std::vector<std::string>> frame_ancestors = base::nullopt;
 };
diff --git a/content/renderer/performance_manager/OWNERS b/content/renderer/performance_manager/OWNERS
new file mode 100644
index 0000000..6ef4e6d
--- /dev/null
+++ b/content/renderer/performance_manager/OWNERS
@@ -0,0 +1 @@
+file://components/performance_manager/OWNERS
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 26bc389..0eee1e5c 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -496,7 +496,7 @@
                   signed_exchange_utils::CreateHeaderIntegrityHashString(
                       exchange->header_integrity)),
               exchange->inner_url, web_response,
-              std::move(exchange->loader_factory_handle).PassPipe()));
+              std::move(exchange->loader_factory_handle)));
     }
   }
 
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc
index b8992e4..d3b3699 100644
--- a/content/renderer/render_frame_impl_browsertest.cc
+++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -397,7 +397,7 @@
 TEST_F(RenderFrameImplTest, NoCrashWhenDeletingFrameDuringFind) {
   frame()->GetWebFrame()->FindForTesting(
       1, "foo", true /* match_case */, true /* forward */,
-      false /* find_next */, true /* force */, false /* wrap_within_frame */);
+      true /* new_session */, true /* force */, false /* wrap_within_frame */);
 
   UnfreezableFrameMsg_Delete delete_message(
       0, FrameDeleteIntention::kNotMainFrame);
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 8a4d954..77df196 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -198,15 +198,14 @@
 }
 
 void ServiceWorkerContextClient::WorkerReadyForInspectionOnInitiatorThread(
-    mojo::ScopedMessagePipeHandle devtools_agent_remote,
-    mojo::ScopedMessagePipeHandle devtools_agent_host_receiver) {
+    blink::CrossVariantMojoRemote<blink::mojom::DevToolsAgentInterfaceBase>
+        devtools_agent_remote,
+    blink::CrossVariantMojoReceiver<
+        blink::mojom::DevToolsAgentHostInterfaceBase>
+        devtools_agent_host_receiver) {
   DCHECK(initiator_thread_task_runner_->RunsTasksInCurrentSequence());
-  mojo::PendingRemote<blink::mojom::DevToolsAgent> agent_remote(
-      std::move(devtools_agent_remote), blink::mojom::DevToolsAgent::Version_);
-  mojo::PendingReceiver<blink::mojom::DevToolsAgentHost> receiver(
-      std::move(devtools_agent_host_receiver));
-  instance_host_->OnReadyForInspection(std::move(agent_remote),
-                                       std::move(receiver));
+  instance_host_->OnReadyForInspection(std::move(devtools_agent_remote),
+                                       std::move(devtools_agent_host_receiver));
 }
 
 void ServiceWorkerContextClient::FailedToFetchClassicScript() {
@@ -246,10 +245,10 @@
   context_ = std::make_unique<WorkerContextData>(this);
 
   DCHECK(pending_service_worker_receiver_.is_valid());
-  proxy_->BindServiceWorker(pending_service_worker_receiver_.PassPipe());
+  proxy_->BindServiceWorker(std::move(pending_service_worker_receiver_));
 
   DCHECK(controller_receiver_.is_valid());
-  proxy_->BindControllerServiceWorker(controller_receiver_.PassPipe());
+  proxy_->BindControllerServiceWorker(std::move(controller_receiver_));
 
   GetContentClient()
       ->renderer()
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index 54ead25..f98e8214 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -133,8 +133,11 @@
 
   // WebServiceWorkerContextClient overrides.
   void WorkerReadyForInspectionOnInitiatorThread(
-      mojo::ScopedMessagePipeHandle devtools_agent_ptr_info,
-      mojo::ScopedMessagePipeHandle devtools_agent_host_request) override;
+      blink::CrossVariantMojoRemote<blink::mojom::DevToolsAgentInterfaceBase>
+          devtools_agent_remote,
+      blink::CrossVariantMojoReceiver<
+          blink::mojom::DevToolsAgentHostInterfaceBase>
+          devtools_agent_host_receiver) override;
   void FailedToFetchClassicScript() override;
   void FailedToFetchModuleScript() override;
   void WorkerScriptLoadedOnWorkerThread() override;
diff --git a/content/shell/renderer/web_test/blink_test_runner.cc b/content/shell/renderer/web_test/blink_test_runner.cc
index 27e7550..3f85635 100644
--- a/content/shell/renderer/web_test/blink_test_runner.cc
+++ b/content/shell/renderer/web_test/blink_test_runner.cc
@@ -283,10 +283,6 @@
     // we will ask the browser to initiate it.
     CaptureLocalPixelsDump();
   } else {
-    // If the browser should capture pixels, then we shouldn't be waiting
-    // for layout dump results. Any test can only require the browser to
-    // dump one or the other at this time.
-    DCHECK(!waiting_for_layout_dump_results_);
     if (test_runner->ShouldDumpSelectionRect()) {
       dump_result_->selection_rect =
           web_frame->GetSelectionBoundsRectForTesting();
diff --git a/content/shell/renderer/web_test/test_runner.cc b/content/shell/renderer/web_test/test_runner.cc
index 6bdc75b..c1267fa 100644
--- a/content/shell/renderer/web_test/test_runner.cc
+++ b/content/shell/renderer/web_test/test_runner.cc
@@ -1120,7 +1120,7 @@
 
   bool match_case = true;
   bool forward = true;
-  bool find_next = true;
+  bool new_session = false;
   bool wrap_around = false;
   for (const auto& option : options_array) {
     if (option == "CaseInsensitive")
@@ -1128,14 +1128,14 @@
     else if (option == "Backwards")
       forward = false;
     else if (option == "StartInSelection")
-      find_next = false;
+      new_session = true;
     else if (option == "WrapAround")
       wrap_around = true;
   }
 
   const bool find_result = GetWebFrame()->FindForTesting(
       0, blink::WebString::FromUTF8(search_text), match_case, forward,
-      find_next, false /* force */, wrap_around);
+      new_session, false /* force */, wrap_around);
   return find_result;
 }
 
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 79bb01a0..5a4c4a6 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1790,6 +1790,7 @@
     "../browser/native_file_system/native_file_system_manager_impl_unittest.cc",
     "../browser/native_io/native_io_context_unittest.cc",
     "../browser/net/cross_origin_embedder_policy_reporter_unittest.cc",
+    "../browser/net/cross_origin_opener_policy_reporter_unittest.cc",
     "../browser/net/network_quality_observer_impl_unittest.cc",
     "../browser/network_context_client_base_impl_unittest.cc",
     "../browser/notification_service_impl_unittest.cc",
diff --git a/content/test/content_browser_test_utils_internal.cc b/content/test/content_browser_test_utils_internal.cc
index a9931b1..0425cc00 100644
--- a/content/test/content_browser_test_utils_internal.cc
+++ b/content/test/content_browser_test_utils_internal.cc
@@ -15,6 +15,7 @@
 
 #include "base/bind.h"
 #include "base/containers/stack.h"
+#include "base/json/json_reader.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/thread_pool.h"
@@ -562,4 +563,66 @@
   return true;
 }
 
+namespace {
+static constexpr int kEnableLogMessageId = 0;
+static constexpr char kEnableLogMessage[] = R"({"id":0,"method":"Log.enable"})";
+static constexpr int kDisableLogMessageId = 1;
+static constexpr char kDisableLogMessage[] =
+    R"({"id":1,"method":"Log.disable"})";
+}  // namespace
+
+DevToolsInspectorLogWatcher::DevToolsInspectorLogWatcher(
+    WebContents* web_contents) {
+  host_ = DevToolsAgentHost::GetOrCreateFor(web_contents);
+  host_->AttachClient(this);
+
+  host_->DispatchProtocolMessage(
+      this, base::as_bytes(
+                base::make_span(kEnableLogMessage, strlen(kEnableLogMessage))));
+
+  run_loop_enable_log_.Run();
+}
+
+DevToolsInspectorLogWatcher::~DevToolsInspectorLogWatcher() {
+  host_->DetachClient(this);
+}
+
+void DevToolsInspectorLogWatcher::DispatchProtocolMessage(
+    DevToolsAgentHost* host,
+    base::span<const uint8_t> message) {
+  base::StringPiece message_str(reinterpret_cast<const char*>(message.data()),
+                                message.size());
+  auto parsed_message = base::JSONReader::Read(message_str);
+  base::Optional<int> command_id = parsed_message->FindIntPath("id");
+  if (command_id.has_value()) {
+    switch (command_id.value()) {
+      case kEnableLogMessageId:
+        run_loop_enable_log_.Quit();
+        break;
+      case kDisableLogMessageId:
+        run_loop_disable_log_.Quit();
+        break;
+      default:
+        NOTREACHED();
+    }
+    return;
+  }
+
+  std::string* notification = parsed_message->FindStringPath("method");
+  if (notification && *notification == "Log.entryAdded") {
+    std::string* text = parsed_message->FindStringPath("params.entry.text");
+    DCHECK(text);
+    last_message_ = *text;
+  }
+}
+
+void DevToolsInspectorLogWatcher::AgentHostClosed(DevToolsAgentHost* host) {}
+
+void DevToolsInspectorLogWatcher::FlushAndStopWatching() {
+  host_->DispatchProtocolMessage(
+      this, base::as_bytes(base::make_span(kDisableLogMessage,
+                                           strlen(kDisableLogMessage))));
+  run_loop_disable_log_.Run();
+}
+
 }  // namespace content
diff --git a/content/test/content_browser_test_utils_internal.h b/content/test/content_browser_test_utils_internal.h
index 3e49c1c1..f2de28fe 100644
--- a/content/test/content_browser_test_utils_internal.h
+++ b/content/test/content_browser_test_utils_internal.h
@@ -23,6 +23,7 @@
 #include "build/build_config.h"
 #include "content/browser/bad_message.h"
 #include "content/common/frame_messages.h"
+#include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/javascript_dialog_manager.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/test/browser_test_utils.h"
@@ -366,6 +367,27 @@
   DISALLOW_COPY_AND_ASSIGN(BeforeUnloadBlockingDelegate);
 };
 
+// A helper class to get DevTools inspector log messages (e.g. network errors).
+class DevToolsInspectorLogWatcher : public DevToolsAgentHostClient {
+ public:
+  explicit DevToolsInspectorLogWatcher(WebContents* web_contents);
+  ~DevToolsInspectorLogWatcher() override;
+
+  void FlushAndStopWatching();
+  std::string last_message() { return last_message_; }
+
+  // DevToolsAgentHostClient:
+  void DispatchProtocolMessage(DevToolsAgentHost* host,
+                               base::span<const uint8_t> message) override;
+  void AgentHostClosed(DevToolsAgentHost* host) override;
+
+ private:
+  scoped_refptr<DevToolsAgentHost> host_;
+  base::RunLoop run_loop_enable_log_;
+  base::RunLoop run_loop_disable_log_;
+  std::string last_message_;
+};
+
 }  // namespace content
 
 #endif  // CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_
diff --git a/content/test/top_frame_population_browsertest.cc b/content/test/top_frame_population_browsertest.cc
index 7236b8ed..62f90e9 100644
--- a/content/test/top_frame_population_browsertest.cc
+++ b/content/test/top_frame_population_browsertest.cc
@@ -36,7 +36,7 @@
               bool unused_is_for_isolated_world) {
             ASSERT_TRUE(params);
 
-            ASSERT_THAT(params->top_frame_origin,
+            ASSERT_THAT(params->isolation_info.top_frame_origin(),
                         Optional(url::Origin::Create(GURL("http://main.com"))));
             ++number_of_frame_loaders;
           }));
@@ -82,7 +82,7 @@
               bool unused_is_for_isolated_world) {
             ASSERT_TRUE(params);
 
-            ASSERT_THAT(params->top_frame_origin,
+            ASSERT_THAT(params->isolation_info.top_frame_origin(),
                         Optional(url::Origin::Create(GURL("http://main.com"))));
             ++number_of_frame_loaders;
           }));
diff --git a/device/fido/cbor_extract.h b/device/fido/cbor_extract.h
index afb88d4..5a99ac6 100644
--- a/device/fido/cbor_extract.h
+++ b/device/fido/cbor_extract.h
@@ -8,6 +8,7 @@
 #include "base/callback_forward.h"
 #include "base/component_export.h"
 #include "base/containers/span.h"
+#include "base/memory/checked_ptr.h"
 #include "components/cbor/values.h"
 
 namespace device {
@@ -216,6 +217,14 @@
 }
 
 template <typename S>
+constexpr StepOrByte<S> Element(
+    const Is required,
+    CheckedPtr<const std::vector<uint8_t>> S::*member,
+    uintptr_t offset) {
+  return ElementImpl<S>(required, offset, internal::Type::kBytestring);
+}
+
+template <typename S>
 constexpr StepOrByte<S> Element(const Is required,
                                 const std::string* S::*member,
                                 uintptr_t offset) {
@@ -224,6 +233,13 @@
 
 template <typename S>
 constexpr StepOrByte<S> Element(const Is required,
+                                CheckedPtr<const std::string> S::*member,
+                                uintptr_t offset) {
+  return ElementImpl<S>(required, offset, internal::Type::kString);
+}
+
+template <typename S>
+constexpr StepOrByte<S> Element(const Is required,
                                 const int64_t* S::*member,
                                 uintptr_t offset) {
   return ElementImpl<S>(required, offset, internal::Type::kInt);
@@ -231,12 +247,27 @@
 
 template <typename S>
 constexpr StepOrByte<S> Element(const Is required,
+                                CheckedPtr<const int64_t> S::*member,
+                                uintptr_t offset) {
+  return ElementImpl<S>(required, offset, internal::Type::kInt);
+}
+
+template <typename S>
+constexpr StepOrByte<S> Element(const Is required,
                                 const std::vector<cbor::Value>* S::*member,
                                 uintptr_t offset) {
   return ElementImpl<S>(required, offset, internal::Type::kArray);
 }
 
 template <typename S>
+constexpr StepOrByte<S> Element(
+    const Is required,
+    CheckedPtr<const std::vector<cbor::Value>> S::*member,
+    uintptr_t offset) {
+  return ElementImpl<S>(required, offset, internal::Type::kArray);
+}
+
+template <typename S>
 constexpr StepOrByte<S> Element(const Is required,
                                 const cbor::Value* S::*member,
                                 uintptr_t offset) {
@@ -245,11 +276,25 @@
 
 template <typename S>
 constexpr StepOrByte<S> Element(const Is required,
+                                CheckedPtr<const cbor::Value> S::*member,
+                                uintptr_t offset) {
+  return ElementImpl<S>(required, offset, internal::Type::kValue);
+}
+
+template <typename S>
+constexpr StepOrByte<S> Element(const Is required,
                                 const bool* S::*member,
                                 uintptr_t offset) {
   return ElementImpl<S>(required, offset, internal::Type::kBoolean);
 }
 
+template <typename S>
+constexpr StepOrByte<S> Element(const Is required,
+                                CheckedPtr<const bool> S::*member,
+                                uintptr_t offset) {
+  return ElementImpl<S>(required, offset, internal::Type::kBoolean);
+}
+
 COMPONENT_EXPORT(DEVICE_FIDO)
 bool Extract(base::span<const void*> outputs,
              base::span<const StepOrByte<void>> steps,
diff --git a/docs/clangd.md b/docs/clangd.md
index a501fd1..a289997a 100644
--- a/docs/clangd.md
+++ b/docs/clangd.md
@@ -13,8 +13,14 @@
 **Googlers:** clangd has been installed on your glinux by default, just use
 `/usr/bin/clangd`.
 
-Alternative: use the following command to build clangd from LLVM source, and you
-will get the binary at
+Alternative: download clangd from the official [Releases](https://github.com/clangd/clangd/releases)
+page.
+
+Note: clangd 10.0.0 does not work with Chromium; use one of the pre-release
+versions lower down on the Releases page until a newer version is released.
+
+If you prefer to build clangd locally, use the following command to build from
+LLVM source, and you will get the binary at
 `out/Release/tools/clang/third_party/llvm/build/bin/clangd`.
 
 ```
@@ -36,8 +42,8 @@
 tools/clang/scripts/generate_compdb.py -p out/Release > compile_commands.json
 ```
 
-Note: the compilation database is not re-generated automatically. You need to
-regenerate it manually whenener build rules change, e.g when you have new files
+Note: the compilation database is not regenerated automatically. You need to
+regenerate it manually whenever build rules change, e.g., when you have new files
 checked in or when you sync to head.
 
 If using Windows PowerShell, use the following command instead to set the
diff --git a/extensions/browser/guest_view/web_view/web_view_find_helper.cc b/extensions/browser/guest_view/web_view/web_view_find_helper.cc
index defb854..95cb7df 100644
--- a/extensions/browser/guest_view/web_view/web_view_find_helper.cc
+++ b/extensions/browser/guest_view/web_view/web_view_find_helper.cc
@@ -103,31 +103,29 @@
   // No duplicate insertions.
   DCHECK(insert_result.second);
 
-  // Find options including the implicit |findNext| field.
   blink::mojom::FindOptionsPtr full_options =
       insert_result.first->second->options().Clone();
 
-  // Set |findNext| implicitly.
   if (current_find_session_) {
     const base::string16& current_search_text =
         current_find_session_->search_text();
     bool current_match_case = current_find_session_->options()->match_case;
-    full_options->find_next = !current_search_text.empty() &&
-                              current_search_text == search_text &&
-                              current_match_case == options->match_case;
+    full_options->new_session = current_search_text.empty() ||
+                                current_search_text != search_text ||
+                                current_match_case != options->match_case;
   } else {
-    full_options->find_next = false;
+    full_options->new_session = true;
   }
 
   // Link find requests that are a part of the same find session.
-  if (full_options->find_next && current_find_session_) {
+  if (!full_options->new_session && current_find_session_) {
     DCHECK(current_find_request_id_ != current_find_session_->request_id());
     current_find_session_->AddFindNextRequest(
         insert_result.first->second->AsWeakPtr());
   }
 
   // Update the current find session, if necessary.
-  if (!full_options->find_next)
+  if (full_options->new_session)
     current_find_session_ = insert_result.first->second;
 
   // Handle the empty |search_text| case internally.
@@ -157,7 +155,7 @@
 
   WebViewFindHelper::FindInfo* find_info = find_iterator->second.get();
   // Handle canceled find requests.
-  if (!find_info->options()->find_next &&
+  if (find_info->options()->new_session &&
       find_info_map_.begin()->first < request_id) {
     DCHECK_NE(current_find_session_->request_id(),
               find_info_map_.begin()->first);
@@ -167,7 +165,7 @@
   }
 
   // Clears the results for |findupdate| for a new find session.
-  if (!find_info->replied() && !find_info->options()->find_next)
+  if (!find_info->replied() && find_info->options()->new_session)
     find_update_event_.reset(new FindUpdateEvent(find_info->search_text()));
 
   // Aggregate the find results.
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc
index bf940650..77876d6 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc
@@ -1065,11 +1065,8 @@
     const gfx::ColorSpace& color_space,
     uint32_t usage,
     base::span<const uint8_t> pixel_data) {
-  auto backing =
-      MakeBacking(mailbox, format, size, color_space, usage, false, pixel_data);
-  if (backing)
-    backing->OnWriteSucceeded();
-  return backing;
+  return MakeBacking(mailbox, format, size, color_space, usage, false,
+                     pixel_data);
 }
 
 bool SharedImageBackingFactoryAHB::CanImportGpuMemoryBuffer(
diff --git a/gpu/command_buffer/service/shared_image_factory.cc b/gpu/command_buffer/service/shared_image_factory.cc
index 59a5565..f11b905 100644
--- a/gpu/command_buffer/service/shared_image_factory.cc
+++ b/gpu/command_buffer/service/shared_image_factory.cc
@@ -213,6 +213,8 @@
     return false;
   auto backing = factory->CreateSharedImage(mailbox, format, size, color_space,
                                             usage, data);
+  if (backing)
+    backing->OnWriteSucceeded();
   return RegisterBacking(std::move(backing), allow_legacy_mailbox);
 }
 
@@ -235,6 +237,8 @@
   auto backing =
       factory->CreateSharedImage(mailbox, client_id, std::move(handle), format,
                                  surface_handle, size, color_space, usage);
+  if (backing)
+    backing->OnWriteSucceeded();
   return RegisterBacking(std::move(backing), allow_legacy_mailbox);
 }
 
diff --git a/gpu/command_buffer/service/wrapped_sk_image.cc b/gpu/command_buffer/service/wrapped_sk_image.cc
index 35043b53..45f136e 100644
--- a/gpu/command_buffer/service/wrapped_sk_image.cc
+++ b/gpu/command_buffer/service/wrapped_sk_image.cc
@@ -219,7 +219,6 @@
         return false;
 
       SetCleared();
-      OnWriteSucceeded();
     } else {
       // Initializing to bright green makes it obvious if the pixels are not
       // properly set before they are displayed (e.g. https://crbug.com/956555).
diff --git a/gpu/ipc/service/shared_image_stub.cc b/gpu/ipc/service/shared_image_stub.cc
index 9428107..5fed5f2 100644
--- a/gpu/ipc/service/shared_image_stub.cc
+++ b/gpu/ipc/service/shared_image_stub.cc
@@ -389,7 +389,7 @@
   }
 }
 
-bool SharedImageStub::MakeContextCurrent() {
+bool SharedImageStub::MakeContextCurrent(bool needs_gl) {
   DCHECK(context_state_);
 
   if (context_state_->context_lost()) {
@@ -401,8 +401,8 @@
   // improve performance. https://crbug.com/457431
   auto* context = context_state_->real_context();
   if (context->IsCurrent(nullptr))
-    return !context_state_->CheckResetStatus(/*needs_gl=*/false);
-  return context_state_->MakeCurrent(/*surface=*/nullptr, /*needs_gl=*/false);
+    return !context_state_->CheckResetStatus(needs_gl);
+  return context_state_->MakeCurrent(/*surface=*/nullptr, needs_gl);
 }
 
 ContextResult SharedImageStub::MakeContextCurrentAndCreateFactory() {
@@ -417,7 +417,9 @@
   }
   DCHECK(context_state_);
   DCHECK(!context_state_->context_lost());
-  if (!MakeContextCurrent()) {
+  // Some shared image backing factories will use GL in ctor, so we need GL even
+  // if chrome is using non-GL backing.
+  if (!MakeContextCurrent(/*needs_gl=*/true)) {
     context_state_ = nullptr;
     return ContextResult::kTransientFailure;
   }
diff --git a/gpu/ipc/service/shared_image_stub.h b/gpu/ipc/service/shared_image_stub.h
index 1bc71f8..b3117d06 100644
--- a/gpu/ipc/service/shared_image_stub.h
+++ b/gpu/ipc/service/shared_image_stub.h
@@ -91,7 +91,7 @@
   void OnReleaseSysmemBufferCollection(gfx::SysmemBufferCollectionId id);
 #endif  // OS_FUCHSIA
 
-  bool MakeContextCurrent();
+  bool MakeContextCurrent(bool needs_gl = false);
   ContextResult MakeContextCurrentAndCreateFactory();
   void OnError();
 
diff --git a/gpu/ipc/shared_image_interface_in_process.cc b/gpu/ipc/shared_image_interface_in_process.cc
index e6eda049..bf11462 100644
--- a/gpu/ipc/shared_image_interface_in_process.cc
+++ b/gpu/ipc/shared_image_interface_in_process.cc
@@ -94,7 +94,7 @@
   completion->Signal();
 }
 
-bool SharedImageInterfaceInProcess::MakeContextCurrent() {
+bool SharedImageInterfaceInProcess::MakeContextCurrent(bool needs_gl) {
   if (!context_state_)
     return false;
 
@@ -105,8 +105,8 @@
   // MakeCurrent to improve performance. https://crbug.com/457431
   auto* context = context_state_->real_context();
   if (context->IsCurrent(nullptr))
-    return !context_state_->CheckResetStatus(/*needs_gl=*/false);
-  return context_state_->MakeCurrent(/*surface=*/nullptr, /*needs_gl=*/false);
+    return !context_state_->CheckResetStatus(needs_gl);
+  return context_state_->MakeCurrent(/*surface=*/nullptr, needs_gl);
 }
 
 void SharedImageInterfaceInProcess::LazyCreateSharedImageFactory() {
@@ -114,6 +114,11 @@
   if (shared_image_factory_)
     return;
 
+  // Some shared image backing factories will use GL in ctor, so we need GL even
+  // if chrome is using non-GL backing.
+  if (!MakeContextCurrent(/*needs_gl=*/true))
+    return;
+
   // We need WrappedSkImage to support creating a SharedImage with pixel data
   // when GL is unavailable. This is used in various unit tests.
   const bool enable_wrapped_sk_image =
diff --git a/gpu/ipc/shared_image_interface_in_process.h b/gpu/ipc/shared_image_interface_in_process.h
index 60b1a3dc3..1b1d698 100644
--- a/gpu/ipc/shared_image_interface_in_process.h
+++ b/gpu/ipc/shared_image_interface_in_process.h
@@ -150,7 +150,7 @@
                        std::vector<SyncToken> sync_token_fences);
 
   // Only called on the gpu thread.
-  bool MakeContextCurrent();
+  bool MakeContextCurrent(bool needs_gl = false);
   void LazyCreateSharedImageFactory();
   void CreateSharedImageOnGpuThread(const Mailbox& mailbox,
                                     viz::ResourceFormat format,
diff --git a/infra/config/generated/commit-queue.cfg b/infra/config/generated/commit-queue.cfg
index dc3fe08..a79cb8e 100644
--- a/infra/config/generated/commit-queue.cfg
+++ b/infra/config/generated/commit-queue.cfg
@@ -730,7 +730,7 @@
       >
       builders: <
         name: "chromium/try/ios-simulator-code-coverage"
-        includable_only: true
+        experiment_percentage: 3
       >
       builders: <
         name: "chromium/try/ios-simulator-cr-recipe"
diff --git a/infra/config/generated/cq-builders.md b/infra/config/generated/cq-builders.md
index 0c728fb2..d3ac896 100644
--- a/infra/config/generated/cq-builders.md
+++ b/infra/config/generated/cq-builders.md
@@ -339,6 +339,9 @@
 * [fuchsia-compile-x64-dbg](https://ci.chromium.org/p/chromium/builders/try/fuchsia-compile-x64-dbg) ([definition](https://cs.chromium.org/search?q=package:%5Echromium$+file:/cq.star$+-file:/beta/+-file:/stable/+fuchsia-compile-x64-dbg)) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+fuchsia-compile-x64-dbg))
   * Experiment percentage: 50
 
+* [ios-simulator-code-coverage](https://ci.chromium.org/p/chromium/builders/try/ios-simulator-code-coverage) ([definition](https://cs.chromium.org/search?q=package:%5Echromium$+file:/cq.star$+-file:/beta/+-file:/stable/+ios-simulator-code-coverage)) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+ios-simulator-code-coverage))
+  * Experiment percentage: 3
+
 * [linux-perfetto-rel](https://ci.chromium.org/p/chromium/builders/try/linux-perfetto-rel) ([definition](https://cs.chromium.org/search?q=package:%5Echromium$+file:/cq.star$+-file:/beta/+-file:/stable/+linux-perfetto-rel)) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+linux-perfetto-rel))
   * Experiment percentage: 100
 
diff --git a/infra/config/subprojects/chromium/master-only/try.star b/infra/config/subprojects/chromium/master-only/try.star
index 7694bf37..01a78ad 100644
--- a/infra/config/subprojects/chromium/master-only/try.star
+++ b/infra/config/subprojects/chromium/master-only/try.star
@@ -574,6 +574,7 @@
     properties = {
         'xcode_build_version': '11e146',
     },
+    tryjob = try_.job(experiment_percentage = 3)
 )
 
 try_.chromium_mac_ios_builder(
diff --git a/ios/build/tools/convert_gn_xcodeproj.py b/ios/build/tools/convert_gn_xcodeproj.py
index d0dc056..1e47839 100755
--- a/ios/build/tools/convert_gn_xcodeproj.py
+++ b/ios/build/tools/convert_gn_xcodeproj.py
@@ -16,6 +16,7 @@
 import collections
 import copy
 import filecmp
+import functools
 import json
 import hashlib
 import os
@@ -37,7 +38,7 @@
     while True:
       self.counter += 1
       str_id = "%s %s %d" % (parent_name, obj['isa'], self.counter)
-      new_id = hashlib.sha1(str_id).hexdigest()[:24].upper()
+      new_id = hashlib.sha1(str_id.encode("utf-8")).hexdigest()[:24].upper()
 
       # Make sure ID is unique. It's possible there could be an id conflict
       # since this is run after GN runs.
@@ -65,7 +66,7 @@
 def WriteXcodeProject(output_path, json_string):
   """Save Xcode project to |output_path| as XML."""
   with tempfile.NamedTemporaryFile() as temp_file:
-    temp_file.write(json_string)
+    temp_file.write(json_string.encode("utf-8"))
     temp_file.flush()
     subprocess.check_call(['plutil', '-convert', 'xml1', temp_file.name])
     CopyFileIfChanged(temp_file.name, output_path)
@@ -85,7 +86,7 @@
   project = XcodeProject(json_data['objects'])
 
   objects_to_remove = []
-  for value in project.objects.values():
+  for value in list(project.objects.values()):
     isa = value['isa']
 
     # Teach build shell script to look for the configuration and platform.
@@ -118,7 +119,7 @@
   AddMarkdownToProject(project, root_dir, source)
   SortFileReferencesByName(project, source)
 
-  objects = collections.OrderedDict(sorted(project.objects.iteritems()))
+  objects = collections.OrderedDict(sorted(project.objects.items()))
   WriteXcodeProject(file_output, json.dumps(json_data))
 
 
@@ -151,6 +152,11 @@
     return object['name']
   return object['path']
 
+try:
+  cmp
+except NameError:
+  def cmp(a, b):
+    return (a > b) - (a < b)
 
 def ObjectComparatorFactory(objects):
   def CompareObjects(ref1, ref2):
@@ -168,7 +174,7 @@
 
 
 def SortFileReferencesByNameWithComparator(project, group_object, comparator):
-  group_object['children'].sort(comparator)
+  group_object['children'].sort(key=functools.cmp_to_key(comparator))
   for key in group_object['children']:
     child = project.objects[key]
     if child['isa'] == 'PBXGroup':
@@ -177,7 +183,7 @@
 
 def AddMarkdownToProject(project, root_dir, group_object):
   list_files_cmd = ['git', '-C', root_dir, 'ls-files', '*.md']
-  paths = subprocess.check_output(list_files_cmd).splitlines()
+  paths = subprocess.check_output(list_files_cmd).decode("utf-8").splitlines()
   ios_internal_dir = os.path.join(root_dir, 'ios_internal')
   if os.path.exists(ios_internal_dir):
     list_files_cmd = ['git', '-C', ios_internal_dir, 'ls-files', '*.md']
diff --git a/ios/build/tools/setup-gn.py b/ios/build/tools/setup-gn.py
index 6d3306e8..ed9d7e6a 100755
--- a/ios/build/tools/setup-gn.py
+++ b/ios/build/tools/setup-gn.py
@@ -12,19 +12,23 @@
 import subprocess
 import sys
 import tempfile
-import ConfigParser
 
 try:
-  import cStringIO as StringIO
+  import configparser
 except ImportError:
-  import StringIO
+  import ConfigParser as configparser
+
+try:
+  import StringIO as io
+except ImportError:
+  import io
 
 
 SUPPORTED_TARGETS = ('iphoneos', 'iphonesimulator')
 SUPPORTED_CONFIGS = ('Debug', 'Release', 'Profile', 'Official', 'Coverage')
 
 
-class ConfigParserWithStringInterpolation(ConfigParser.SafeConfigParser):
+class ConfigParserWithStringInterpolation(configparser.SafeConfigParser):
 
   '''A .ini file parser that supports strings and environment variables.'''
 
@@ -32,8 +36,8 @@
 
   def values(self, section):
     return map(
-        lambda (k, v): self._UnquoteString(self._ExpandEnvVar(v)),
-        ConfigParser.SafeConfigParser.items(self, section))
+        lambda kv: self._UnquoteString(self._ExpandEnvVar(kv[1])),
+        configparser.ConfigParser.items(self, section))
 
   def getstring(self, section, option):
     return self._UnquoteString(self._ExpandEnvVar(self.get(section, option)))
@@ -123,7 +127,7 @@
 
 
   def Generate(self, gn_path, root_path, out_path):
-    buf = StringIO.StringIO()
+    buf = io.StringIO()
     self.WriteArgsGn(buf)
     WriteToFileIfChanged(
         os.path.join(out_path, 'args.gn'),
@@ -134,14 +138,14 @@
         self.GetGnCommand(gn_path, root_path, out_path, True))
 
   def CreateGnRules(self, gn_path, root_path, out_path):
-    buf = StringIO.StringIO()
+    buf = io.StringIO()
     self.WriteArgsGn(buf)
     WriteToFileIfChanged(
         os.path.join(out_path, 'args.gn'),
         buf.getvalue(),
         overwrite=True)
 
-    buf = StringIO.StringIO()
+    buf = io.StringIO()
     gn_command = self.GetGnCommand(gn_path, root_path, out_path, False)
     self.WriteBuildNinja(buf, gn_command)
     WriteToFileIfChanged(
@@ -149,7 +153,7 @@
         buf.getvalue(),
         overwrite=False)
 
-    buf = StringIO.StringIO()
+    buf = io.StringIO()
     self.WriteBuildNinjaDeps(buf)
     WriteToFileIfChanged(
         os.path.join(out_path, 'build.ninja.d'),
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index 8034e33..3650973 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -187,6 +187,7 @@
     "//ios/chrome/browser/crash_report:crash_report_internal",
     "//ios/chrome/browser/crash_report/breadcrumbs",
     "//ios/chrome/browser/crash_report/breadcrumbs:feature_flags",
+    "//ios/chrome/browser/credential_provider",
     "//ios/chrome/browser/download",
     "//ios/chrome/browser/external_files",
     "//ios/chrome/browser/favicon",
diff --git a/ios/chrome/app/application_delegate/app_state.mm b/ios/chrome/app/application_delegate/app_state.mm
index dad74f6..1b2af68 100644
--- a/ios/chrome/app/application_delegate/app_state.mm
+++ b/ios/chrome/app/application_delegate/app_state.mm
@@ -184,6 +184,15 @@
   _safeModeCoordinator = safeModeCoordinator;
 }
 
+- (void)setSceneShowingBlockingUI:(SceneState*)newScene {
+  _sceneShowingBlockingUI = newScene;
+  if (!newScene) {
+    for (SceneState* scene in self.connectedScenes) {
+      scene.presentingModalOverlay = false;
+    }
+  }
+}
+
 #pragma mark - Public methods.
 
 - (void)applicationDidEnterBackground:(UIApplication*)application
@@ -536,6 +545,7 @@
 #pragma mark - SafeModeCoordinatorDelegate Implementation
 
 - (void)coordinatorDidExitSafeMode:(nonnull SafeModeCoordinator*)coordinator {
+  self.sceneShowingBlockingUI = nil;
   self.safeModeCoordinator = nil;
   self.inSafeMode = NO;
   [_browserLauncher startUpBrowserToStage:INITIALIZATION_STAGE_FOREGROUND];
@@ -559,6 +569,8 @@
   [self.foregroundActiveScene.window makeKeyAndVisible];
 
   [self.safeModeCoordinator start];
+
+  self.sceneShowingBlockingUI = self.foregroundActiveScene;
 }
 
 - (void)initializeUI {
@@ -603,13 +615,14 @@
 - (void)sceneDidActivate:(NSNotification*)notification {
   DCHECK(IsSceneStartupSupported());
   if (@available(iOS 13, *)) {
+    UIWindowScene* scene =
+        base::mac::ObjCCastStrict<UIWindowScene>(notification.object);
+    SceneDelegate* sceneDelegate =
+        base::mac::ObjCCastStrict<SceneDelegate>(scene.delegate);
+
     if (!self.firstSceneHasActivated) {
       self.firstSceneHasActivated = YES;
 
-      UIWindowScene* scene =
-          base::mac::ObjCCastStrict<UIWindowScene>(notification.object);
-      SceneDelegate* sceneDelegate =
-          base::mac::ObjCCastStrict<SceneDelegate>(scene.delegate);
       [self.observers appState:self
            firstSceneActivated:sceneDelegate.sceneState];
 
@@ -618,10 +631,10 @@
         // safe mode has been postponed until now.
         [self startSafeMode];
       }
-      sceneDelegate.sceneState.presentingModalOverlay =
-          self.sceneShowingBlockingUI &&
-          (self.sceneShowingBlockingUI != sceneDelegate.sceneState);
     }
+    sceneDelegate.sceneState.presentingModalOverlay =
+        self.sceneShowingBlockingUI &&
+        (self.sceneShowingBlockingUI != sceneDelegate.sceneState);
   }
 }
 
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 17b566a..3fdb0e4 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -51,6 +51,8 @@
 #include "ios/chrome/browser/crash_report/crash_keys_helper.h"
 #include "ios/chrome/browser/crash_report/crash_loop_detection_util.h"
 #include "ios/chrome/browser/crash_report/crash_report_helper.h"
+#include "ios/chrome/browser/credential_provider/credential_provider_service_factory.h"
+#include "ios/chrome/browser/credential_provider/credential_provider_support.h"
 #include "ios/chrome/browser/download/download_directory_util.h"
 #import "ios/chrome/browser/external_files/external_file_remover_factory.h"
 #import "ios/chrome/browser/external_files/external_file_remover_impl.h"
@@ -256,9 +258,6 @@
 
   // Hander for the startup tasks, deferred or not.
   StartupTasks* _startupTasks;
-
-  // If the animations were disabled.
-  BOOL _animationDisabled;
 }
 
 // The ChromeBrowserState associated with the main (non-OTR) browsing mode.
@@ -516,6 +515,10 @@
       ShareExtensionServiceFactory::GetForBrowserState(self.mainBrowserState);
   service->Initialize();
 
+  if (IsCredentialProviderExtensionSupported()) {
+    CredentialProviderServiceFactory::GetForBrowserState(self.mainBrowserState);
+  }
+
   if ([PreviousSessionInfo sharedInstance].isFirstSessionAfterLanguageChange) {
     IOSChromeContentSuggestionsServiceFactory::GetForBrowserState(
         chromeBrowserState)
@@ -652,6 +655,9 @@
 #pragma mark - Property implementation.
 
 - (id<BrowserInterfaceProvider>)interfaceProvider {
+  if (self.appState.foregroundActiveScene) {
+    return self.appState.foregroundActiveScene.interfaceProvider;
+  }
   return self.appState.connectedScenes[0].interfaceProvider;
 }
 
@@ -759,34 +765,6 @@
            object:nil];
 }
 
-- (void)registerBatteryMonitoringNotifications {
-  if (base::FeatureList::IsEnabled(kDisableAnimationOnLowBattery)) {
-    [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
-    [[NSNotificationCenter defaultCenter]
-        addObserver:self
-           selector:@selector(batteryLevelDidChange:)
-               name:UIDeviceBatteryLevelDidChangeNotification
-             object:nil];
-    [self batteryLevelDidChange:nil];
-  }
-}
-
-- (void)batteryLevelDidChange:(NSNotification*)notification {
-  if (![[UIDevice currentDevice] isBatteryMonitoringEnabled]) {
-    return;
-  }
-  CGFloat level = [UIDevice currentDevice].batteryLevel;
-  if (level < web::features::kLowBatteryLevelThreshold) {
-    if (!_animationDisabled) {
-      _animationDisabled = YES;
-      [UIView setAnimationsEnabled:NO];
-    }
-  } else if (_animationDisabled) {
-    _animationDisabled = NO;
-    [UIView setAnimationsEnabled:YES];
-  }
-}
-
 - (void)schedulePrefObserverInitialization {
   [[DeferredInitializationRunner sharedInstance]
       enqueueBlockNamed:kPrefObserverInit
@@ -979,8 +957,6 @@
   [_startupTasks initializeOmaha];
   [_startupTasks donateIntents];
 
-  [self registerBatteryMonitoringNotifications];
-
   // Deferred tasks.
   [self schedulePrefObserverInitialization];
   [self scheduleMemoryDebuggingTools];
diff --git a/ios/chrome/app/strings/resources/ios_strings_es-419.xtb b/ios/chrome/app/strings/resources/ios_strings_es-419.xtb
index 16643d5..39eeb52 100644
--- a/ios/chrome/app/strings/resources/ios_strings_es-419.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_es-419.xtb
@@ -376,6 +376,7 @@
 <translation id="5869029295770560994">Entendido</translation>
 <translation id="5871497086027727873">1 artículo movido</translation>
 <translation id="5897956970858271241">Visitar el vínculo copiado</translation>
+<translation id="5899314093904173337">Para habilitar el uso compartido con personas cercanas, permíteles que escaneen este código QR con la cámara o una app de lectura de código QR</translation>
 <translation id="5911030830365207728">Google Traductor</translation>
 <translation id="5913600720976431809">Opciones para traducir la página</translation>
 <translation id="5938160824633642847">El dispositivo está casi lleno. Libera espacio y vuelve a intentarlo.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_ne.xtb b/ios/chrome/app/strings/resources/ios_strings_ne.xtb
index 630c18f..15eb890 100644
--- a/ios/chrome/app/strings/resources/ios_strings_ne.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_ne.xtb
@@ -376,6 +376,7 @@
 <translation id="5869029295770560994">ठिक छ, बुझेँ</translation>
 <translation id="5871497086027727873">1 वस्तु सारियो</translation>
 <translation id="5897956970858271241">प्रतिलिपि गरिएको लिंकमा जानुहोस्</translation>
+<translation id="5899314093904173337">वरपर रहेका मान्छेहरूसँग सेयर गर्न उनीहरूलाई क्यामेरा वा QR स्क्यान गर्ने एप प्रयोग गरी यो QR कोड स्क्यान गर्न लगाउनुहोस्</translation>
 <translation id="5911030830365207728">Google अनुवादक</translation>
 <translation id="5913600720976431809">यो पृष्ठ अनुवाद गर्ने विकल्पहरू</translation>
 <translation id="5938160824633642847">तपाईंको यन्त्रको भण्डारण स्थान लगभग भरिएको छ। भण्डारण स्थान खाली गरी फेरि प्रयास गर्नुहोस्।</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_zh-TW.xtb b/ios/chrome/app/strings/resources/ios_strings_zh-TW.xtb
index 937f9f6..c1ecd199 100644
--- a/ios/chrome/app/strings/resources/ios_strings_zh-TW.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_zh-TW.xtb
@@ -376,6 +376,7 @@
 <translation id="5869029295770560994">好,我知道了</translation>
 <translation id="5871497086027727873">已移動 1 個項目</translation>
 <translation id="5897956970858271241">前往複製的連結</translation>
+<translation id="5899314093904173337">如要與附近的使用者分享,請讓對方使用相機或 QR 掃描器應用程式掃描這個 QR 圖碼</translation>
 <translation id="5911030830365207728">Google 翻譯</translation>
 <translation id="5913600720976431809">網頁翻譯選項</translation>
 <translation id="5938160824633642847">你的裝置空間即將用盡,請在釋出空間後再試一次。</translation>
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc b/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc
index dde7cf2..8362089 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc
@@ -28,8 +28,6 @@
 #include "ios/chrome/browser/browser_state_metrics/browser_state_metrics.h"
 #include "ios/chrome/browser/chrome_constants.h"
 #include "ios/chrome/browser/chrome_paths.h"
-#include "ios/chrome/browser/credential_provider/credential_provider_service_factory.h"
-#include "ios/chrome/browser/credential_provider/credential_provider_support.h"
 #include "ios/chrome/browser/pref_names.h"
 #include "ios/chrome/browser/signin/account_consistency_service_factory.h"
 #include "ios/chrome/browser/signin/account_reconcilor_factory.h"
@@ -212,10 +210,6 @@
   // Initialization needs to happen after the browser context is available
   // because UnifiedConsentService's dependencies needs the URL context getter.
   UnifiedConsentServiceFactory::GetForBrowserState(browser_state);
-
-  if (IsCredentialProviderExtensionSupported()) {
-    CredentialProviderServiceFactory::GetForBrowserState(browser_state);
-  }
 }
 
 void ChromeBrowserStateManagerImpl::AddBrowserStateToCache(
diff --git a/ios/chrome/browser/credential_provider/BUILD.gn b/ios/chrome/browser/credential_provider/BUILD.gn
index 83606af..983931c0 100644
--- a/ios/chrome/browser/credential_provider/BUILD.gn
+++ b/ios/chrome/browser/credential_provider/BUILD.gn
@@ -28,8 +28,10 @@
     "//components/password_manager/core/browser:affiliation",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/passwords",
+    "//ios/chrome/browser/signin",
     "//ios/chrome/common/app_group",
     "//ios/chrome/common/credential_provider",
+    "//ios/public/provider/chrome/browser/signin",
     "//url",
   ]
   libs = [
@@ -58,9 +60,13 @@
     "//base/test:test_support",
     "//components/autofill/core/common",
     "//components/password_manager/core/browser:test_support",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/signin:test_support",
     "//ios/chrome/common/app_group",
     "//ios/chrome/common/credential_provider",
     "//ios/chrome/common/credential_provider:ui",
+    "//ios/web/public/test",
     "//testing/gtest",
     "//url",
   ]
diff --git a/ios/chrome/browser/credential_provider/credential_provider_service.h b/ios/chrome/browser/credential_provider/credential_provider_service.h
index f3044b2..92bcc288 100644
--- a/ios/chrome/browser/credential_provider/credential_provider_service.h
+++ b/ios/chrome/browser/credential_provider/credential_provider_service.h
@@ -9,6 +9,7 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "components/password_manager/core/browser/password_store_consumer.h"
+#import "ios/chrome/browser/signin/authentication_service.h"
 
 @class ArchivableCredentialStore;
 
@@ -22,6 +23,7 @@
   // Initializes the service.
   CredentialProviderService(
       scoped_refptr<password_manager::PasswordStore> password_store,
+      AuthenticationService* authentication_service,
       ArchivableCredentialStore* credential_store);
   ~CredentialProviderService() override;
 
@@ -47,9 +49,15 @@
   // The interface for getting and manipulating a user's saved passwords.
   scoped_refptr<password_manager::PasswordStore> password_store_;
 
+  // The interface for getting the primary account identifier.
+  AuthenticationService* authentication_service_ = nullptr;
+
   // The interface for saving and updating credentials.
   ArchivableCredentialStore* archivable_credential_store_ = nil;
 
+  // The current validation ID or nil.
+  NSString* account_validation_id_ = nil;
+
   DISALLOW_COPY_AND_ASSIGN(CredentialProviderService);
 };
 
diff --git a/ios/chrome/browser/credential_provider/credential_provider_service.mm b/ios/chrome/browser/credential_provider/credential_provider_service.mm
index 4a94f56a..f5334a9 100644
--- a/ios/chrome/browser/credential_provider/credential_provider_service.mm
+++ b/ios/chrome/browser/credential_provider/credential_provider_service.mm
@@ -19,6 +19,7 @@
 #import "ios/chrome/common/credential_provider/archivable_credential_store.h"
 #import "ios/chrome/common/credential_provider/as_password_credential_identity+credential.h"
 #import "ios/chrome/common/credential_provider/constants.h"
+#import "ios/public/provider/chrome/browser/signin/chrome_identity.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -78,11 +79,12 @@
       getCredentialIdentityStoreStateWithCompletion:stateCompletion];
 }
 
-ArchivableCredential* CredentialFromForm(const PasswordForm& form) {
+ArchivableCredential* CredentialFromForm(const PasswordForm& form,
+                                         NSString* validation_id) {
   ArchivableCredential* credential =
       [[ArchivableCredential alloc] initWithPasswordForm:form
                                                  favicon:nil
-                                    validationIdentifier:nil];
+                                    validationIdentifier:validation_id];
   if (!credential) {
     // Verify that the credential is nil because it's an Android one or
     // blacklisted.
@@ -96,13 +98,20 @@
 
 CredentialProviderService::CredentialProviderService(
     scoped_refptr<PasswordStore> password_store,
+    AuthenticationService* authentication_service,
     ArchivableCredentialStore* credential_store)
     : password_store_(password_store),
+      authentication_service_(authentication_service),
       archivable_credential_store_(credential_store) {
   DCHECK(password_store_);
   password_store_->AddObserver(this);
-  // TODO(crbug.com/1066803): Wait for things to settle down before syncs, and
-  // sync credentials after Sync finishes or some seconds in the future.
+
+  DCHECK(authentication_service_);
+  account_validation_id_ =
+      authentication_service_->GetAuthenticatedIdentity().gaiaID;
+  // TODO(crbug.com/1066803): Wait for things to settle down before
+  // syncs, and sync credentials after Sync finishes or some
+  // seconds in the future.
   if (ShouldSyncASIdentityStore()) {
     SyncASIdentityStore(credential_store);
   }
@@ -123,7 +132,8 @@
     std::vector<std::unique_ptr<PasswordForm>> results) {
   [archivable_credential_store_ removeAllCredentials];
   for (const auto& form : results) {
-    ArchivableCredential* credential = CredentialFromForm(*form);
+    ArchivableCredential* credential =
+        CredentialFromForm(*form, account_validation_id_);
     if (credential) {
       [archivable_credential_store_ addCredential:credential];
     }
@@ -150,7 +160,8 @@
 void CredentialProviderService::OnLoginsChanged(
     const PasswordStoreChangeList& changes) {
   for (const PasswordStoreChange& change : changes) {
-    ArchivableCredential* credential = CredentialFromForm(change.form());
+    ArchivableCredential* credential =
+        CredentialFromForm(change.form(), account_validation_id_);
     if (!credential) {
       continue;
     }
diff --git a/ios/chrome/browser/credential_provider/credential_provider_service_factory.mm b/ios/chrome/browser/credential_provider/credential_provider_service_factory.mm
index 69f812db..3974803 100644
--- a/ios/chrome/browser/credential_provider/credential_provider_service_factory.mm
+++ b/ios/chrome/browser/credential_provider/credential_provider_service_factory.mm
@@ -9,6 +9,7 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/credential_provider/credential_provider_service.h"
 #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
+#import "ios/chrome/browser/signin/authentication_service_factory.h"
 #import "ios/chrome/common/credential_provider/archivable_credential_store.h"
 #import "ios/chrome/common/credential_provider/constants.h"
 
@@ -35,6 +36,7 @@
           "CredentialProviderService",
           BrowserStateDependencyManager::GetInstance()) {
   DependsOn(IOSChromePasswordStoreFactory::GetInstance());
+  DependsOn(AuthenticationServiceFactory::GetInstance());
 }
 
 CredentialProviderServiceFactory::~CredentialProviderServiceFactory() = default;
@@ -47,9 +49,11 @@
   scoped_refptr<password_manager::PasswordStore> password_store =
       IOSChromePasswordStoreFactory::GetForBrowserState(
           browser_state, ServiceAccessType::IMPLICIT_ACCESS);
+  AuthenticationService* authentication_service =
+      AuthenticationServiceFactory::GetForBrowserState(browser_state);
   ArchivableCredentialStore* credential_store =
       [[ArchivableCredentialStore alloc]
           initWithFileURL:CredentialProviderSharedArchivableStoreURL()];
-  return std::make_unique<CredentialProviderService>(password_store,
-                                                     credential_store);
+  return std::make_unique<CredentialProviderService>(
+      password_store, authentication_service, credential_store);
 }
diff --git a/ios/chrome/browser/credential_provider/credential_provider_service_unittest.mm b/ios/chrome/browser/credential_provider/credential_provider_service_unittest.mm
index a2381386..f0883a9ab 100644
--- a/ios/chrome/browser/credential_provider/credential_provider_service_unittest.mm
+++ b/ios/chrome/browser/credential_provider/credential_provider_service_unittest.mm
@@ -7,13 +7,16 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/strings/utf_string_conversions.h"
 #import "base/test/ios/wait_util.h"
-#include "base/test/task_environment.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/password_store_default.h"
+#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
+#include "ios/chrome/browser/signin/authentication_service_factory.h"
+#import "ios/chrome/browser/signin/authentication_service_fake.h"
 #include "ios/chrome/common/app_group/app_group_constants.h"
 #import "ios/chrome/common/credential_provider/archivable_credential_store.h"
 #import "ios/chrome/common/credential_provider/constants.h"
 #import "ios/chrome/common/credential_provider/credential.h"
+#include "ios/web/public/test/web_task_environment.h"
 #import "testing/gtest_mac.h"
 #include "testing/platform_test.h"
 
@@ -31,7 +34,8 @@
 
 class CredentialProviderServiceTest : public PlatformTest {
  public:
-  CredentialProviderServiceTest() {}
+  CredentialProviderServiceTest()
+      : chrome_browser_state_(TestChromeBrowserState::Builder().Build()) {}
 
   void SetUp() override {
     PlatformTest::SetUp();
@@ -43,8 +47,19 @@
     EXPECT_FALSE([shared_defaults
         boolForKey:kUserDefaultsCredentialProviderFirstTimeSyncCompleted]);
     credential_store_ = [[ArchivableCredentialStore alloc] initWithFileURL:nil];
+
+    TestChromeBrowserState::Builder builder;
+    builder.AddTestingFactory(
+        AuthenticationServiceFactory::GetInstance(),
+        base::BindRepeating(
+            &AuthenticationServiceFake::CreateAuthenticationService));
+    chrome_browser_state_ = builder.Build();
+    AuthenticationService* authentication_service =
+        AuthenticationServiceFactory::GetForBrowserState(
+            chrome_browser_state_.get());
+
     credential_provider_service_ = std::make_unique<CredentialProviderService>(
-        password_store_, credential_store_);
+        password_store_, authentication_service, credential_store_);
   }
 
   void TearDown() override {
@@ -69,10 +84,11 @@
   }
 
   base::ScopedTempDir temp_dir_;
-  base::test::TaskEnvironment task_environment_;
+  web::WebTaskEnvironment task_environment_;
   std::unique_ptr<CredentialProviderService> credential_provider_service_;
   scoped_refptr<PasswordStoreDefault> password_store_;
   ArchivableCredentialStore* credential_store_;
+  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
 
   DISALLOW_COPY_AND_ASSIGN(CredentialProviderServiceTest);
 };
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index c9e80bd..f293c2d 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -480,10 +480,10 @@
      flag_descriptions::kConfirmInfobarMessagesUIName,
      flag_descriptions::kConfirmInfobarMessagesUIDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kConfirmInfobarMessagesUI)},
-    {"disable-animation-on-low-battery",
-     flag_descriptions::kDisableAnimationOnLowBatteryName,
-     flag_descriptions::kDisableAnimationOnLowBatteryDescription,
-     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kDisableAnimationOnLowBattery)},
+    {"disable-progress-bar-animation",
+     flag_descriptions::kDisableProgressBarAnimationName,
+     flag_descriptions::kDisableProgressBarAnimationDescription,
+     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kDisableProgressBarAnimation)},
     {"messages-save-card-infobar",
      flag_descriptions::kSaveCardInfobarMessagesUIName,
      flag_descriptions::kSaveCardInfobarMessagesUIDescription, flags_ui::kOsIos,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index 909b6cf..29ea56d 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -179,10 +179,10 @@
     "A crash report will be uploaded if the main thread is frozen more than "
     "the time specified by this flag.";
 
-const char kDisableAnimationOnLowBatteryName[] =
-    "Disable animations on low battery";
-const char kDisableAnimationOnLowBatteryDescription[] =
-    "Disable animations when battery level goes below 20%";
+const char kDisableProgressBarAnimationName[] =
+    "Disable page load progress bar animation";
+const char kDisableProgressBarAnimationDescription[] =
+    "Disable progress bar animation when a page loads.";
 
 const char kDiscoverFeedInNtpName[] = "Enable Discover feed in new tab page";
 const char kDiscoverFeedInNtpDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index 6b8d6727..25f1f9d 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -147,10 +147,9 @@
 extern const char kDetectMainThreadFreezeName[];
 extern const char kDetectMainThreadFreezeDescription[];
 
-// Title and description for the flag to disable animations when battery
-// level is below a certain level.
-extern const char kDisableAnimationOnLowBatteryName[];
-extern const char kDisableAnimationOnLowBatteryDescription[];
+// Title and description for the flag to disable progress bar animation.
+extern const char kDisableProgressBarAnimationName[];
+extern const char kDisableProgressBarAnimationDescription[];
 
 // Title and description for the flag to replace the Zine feed with the
 // Discover feed in the Bling NTP.
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/BUILD.gn b/ios/chrome/browser/infobars/overlays/browser_agent/BUILD.gn
index 167b5a5..01013bc7 100644
--- a/ios/chrome/browser/infobars/overlays/browser_agent/BUILD.gn
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/BUILD.gn
@@ -32,6 +32,7 @@
     "//base",
     "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/confirm",
     "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords",
+    "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate",
     "//ios/chrome/browser/main:public",
     "//ios/chrome/browser/ui/infobars:feature_flags",
   ]
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.mm b/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.mm
index edee5ee..c7cac37 100644
--- a/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.mm
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.mm
@@ -8,6 +8,7 @@
 #import "ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent.h"
 #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/confirm/confirm_infobar_interaction_handler.h"
 #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_interaction_handler.h"
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_interaction_handler.h"
 #import "ios/chrome/browser/ui/infobars/infobar_feature.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -24,6 +25,8 @@
       std::make_unique<PasswordInfobarInteractionHandler>(browser));
   browser_agent->AddInfobarInteractionHandler(
       std::make_unique<ConfirmInfobarInteractionHandler>());
+  browser_agent->AddInfobarInteractionHandler(
+      std::make_unique<TranslateInfobarInteractionHandler>());
   // TODO(crbug.com/1030357): Add InfobarInteractionHandlers for each
   // InfobarType when implemented.
 }
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/BUILD.gn b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/BUILD.gn
index dd9040c..fff9c6fb 100644
--- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/BUILD.gn
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/BUILD.gn
@@ -7,6 +7,8 @@
   sources = [
     "mock_infobar_interaction_handler.h",
     "mock_infobar_interaction_handler.mm",
+    "mock_translate_infobar_interaction_handler.h",
+    "mock_translate_infobar_interaction_handler.mm",
   ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
@@ -16,6 +18,7 @@
     "//ios/chrome/browser/infobars:public",
     "//ios/chrome/browser/infobars/overlays",
     "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers",
+    "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate",
     "//ios/chrome/browser/overlays",
     "//ios/chrome/browser/overlays/public/common/infobars",
     "//ios/chrome/browser/overlays/public/infobar_banner",
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_translate_infobar_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_translate_infobar_interaction_handler.h
new file mode 100644
index 0000000..4c0309c
--- /dev/null
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_translate_infobar_interaction_handler.h
@@ -0,0 +1,32 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TEST_MOCK_TRANSLATE_INFOBAR_INTERACTION_HANDLER_H_
+#define IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TEST_MOCK_TRANSLATE_INFOBAR_INTERACTION_HANDLER_H_
+
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+
+// Mock version of TranslateInfobarModalInteractionHandler for use in tests.
+class MockTranslateInfobarModalInteractionHandler
+    : public TranslateInfobarModalInteractionHandler {
+ public:
+  MockTranslateInfobarModalInteractionHandler();
+  ~MockTranslateInfobarModalInteractionHandler();
+
+  MOCK_METHOD1(ToggleAlwaysTranslate, void(InfoBarIOS* infobar));
+  MOCK_METHOD1(ToggleNeverTranslateLanguage, void(InfoBarIOS* infobar));
+  MOCK_METHOD1(ToggleNeverTranslateSite, void(InfoBarIOS* infobar));
+  MOCK_METHOD1(RevertTranslation, void(InfoBarIOS* infobar));
+  MOCK_METHOD3(UpdateLanguages,
+               void(InfoBarIOS* infobar,
+                    int source_language_index,
+                    int target_language_index));
+  MOCK_METHOD1(PerformMainAction, void(InfoBarIOS* infobar));
+  MOCK_METHOD2(InfobarVisibilityChanged,
+               void(InfoBarIOS* infobar, bool visible));
+};
+
+#endif  // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TEST_MOCK_TRANSLATE_INFOBAR_INTERACTION_HANDLER_H_
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_translate_infobar_interaction_handler.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_translate_infobar_interaction_handler.mm
new file mode 100644
index 0000000..4fa78b49
--- /dev/null
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_translate_infobar_interaction_handler.mm
@@ -0,0 +1,15 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_translate_infobar_interaction_handler.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+MockTranslateInfobarModalInteractionHandler::
+    MockTranslateInfobarModalInteractionHandler() = default;
+
+MockTranslateInfobarModalInteractionHandler::
+    ~MockTranslateInfobarModalInteractionHandler() = default;
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/BUILD.gn b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/BUILD.gn
new file mode 100644
index 0000000..869dd4f
--- /dev/null
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/BUILD.gn
@@ -0,0 +1,66 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("translate") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "translate_infobar_banner_interaction_handler.h",
+    "translate_infobar_banner_interaction_handler.mm",
+    "translate_infobar_interaction_handler.h",
+    "translate_infobar_interaction_handler.mm",
+    "translate_infobar_modal_interaction_handler.h",
+    "translate_infobar_modal_interaction_handler.mm",
+    "translate_infobar_modal_overlay_request_callback_installer.h",
+    "translate_infobar_modal_overlay_request_callback_installer.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/translate/core/browser",
+    "//ios/chrome/browser/infobars",
+    "//ios/chrome/browser/infobars:public",
+    "//ios/chrome/browser/infobars/overlays",
+    "//ios/chrome/browser/infobars/overlays:util",
+    "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers:interaction_handlers",
+    "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common",
+    "//ios/chrome/browser/main:public",
+    "//ios/chrome/browser/overlays",
+    "//ios/chrome/browser/overlays/public/infobar_banner",
+    "//ios/chrome/browser/overlays/public/infobar_modal",
+    "//ios/chrome/browser/web_state_list",
+  ]
+}
+
+source_set("unit_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "translate_infobar_banner_interaction_handler_unittest.mm",
+    "translate_infobar_modal_interaction_handler_unittest.mm",
+    "translate_infobar_modal_overlay_request_callback_installer_unittest.mm",
+  ]
+  deps = [
+    ":translate",
+    "//base/test:test_support",
+    "//components/infobars/core:feature_flags",
+    "//components/translate/core/browser:test_support",
+    "//ios/chrome/browser/infobars",
+    "//ios/chrome/browser/infobars/overlays",
+    "//ios/chrome/browser/infobars/overlays:util",
+    "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common",
+    "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test",
+    "//ios/chrome/browser/infobars/test",
+    "//ios/chrome/browser/main:test_support",
+    "//ios/chrome/browser/overlays",
+    "//ios/chrome/browser/overlays/public/common",
+    "//ios/chrome/browser/overlays/public/infobar_banner",
+    "//ios/chrome/browser/overlays/public/infobar_modal",
+    "//ios/chrome/browser/overlays/test",
+    "//ios/chrome/browser/ui/infobars:feature_flags",
+    "//ios/chrome/browser/ui/infobars:infobars_ui",
+    "//ios/chrome/browser/ui/infobars/test",
+    "//ios/chrome/browser/web_state_list",
+    "//ios/web/public/test/fakes",
+    "//testing/gtest",
+  ]
+}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_banner_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_banner_interaction_handler.h
new file mode 100644
index 0000000..091e610
--- /dev/null
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_banner_interaction_handler.h
@@ -0,0 +1,29 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TRANSLATE_TRANSLATE_INFOBAR_BANNER_INTERACTION_HANDLER_H_
+#define IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TRANSLATE_TRANSLATE_INFOBAR_BANNER_INTERACTION_HANDLER_H_
+
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_banner_interaction_handler.h"
+
+#include "base/scoped_observer.h"
+#include "components/translate/core/browser/translate_infobar_delegate.h"
+
+// Helper object that updates the model layer for interaction events with the
+// Translate infobar banner UI.
+class TranslateInfobarBannerInteractionHandler
+    : public InfobarBannerInteractionHandler {
+ public:
+  TranslateInfobarBannerInteractionHandler();
+  ~TranslateInfobarBannerInteractionHandler() override;
+
+  // InfobarBannerInteractionHandler:
+  void MainButtonTapped(InfoBarIOS* infobar) override;
+
+ private:
+  // Returns the password delegate from |infobar|.
+  translate::TranslateInfoBarDelegate* GetInfobarDelegate(InfoBarIOS* infobar);
+};
+
+#endif  // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TRANSLATE_TRANSLATE_INFOBAR_BANNER_INTERACTION_HANDLER_H_
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_banner_interaction_handler.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_banner_interaction_handler.mm
new file mode 100644
index 0000000..b4b233fa
--- /dev/null
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_banner_interaction_handler.mm
@@ -0,0 +1,54 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_banner_interaction_handler.h"
+
+#include "ios/chrome/browser/infobars/infobar_ios.h"
+#import "ios/chrome/browser/overlays/public/infobar_banner/translate_infobar_banner_overlay_request_config.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+using translate_infobar_overlays::TranslateBannerRequestConfig;
+
+#pragma mark - InfobarBannerInteractionHandler
+
+TranslateInfobarBannerInteractionHandler::
+    TranslateInfobarBannerInteractionHandler()
+    : InfobarBannerInteractionHandler(
+          TranslateBannerRequestConfig::RequestSupport()) {}
+
+TranslateInfobarBannerInteractionHandler::
+    ~TranslateInfobarBannerInteractionHandler() = default;
+
+void TranslateInfobarBannerInteractionHandler::MainButtonTapped(
+    InfoBarIOS* infobar) {
+  translate::TranslateInfoBarDelegate* delegate = GetInfobarDelegate(infobar);
+  translate::TranslateStep step = delegate->translate_step();
+  switch (step) {
+    case translate::TranslateStep::TRANSLATE_STEP_BEFORE_TRANSLATE:
+      delegate->Translate();
+      break;
+    case translate::TranslateStep::TRANSLATE_STEP_AFTER_TRANSLATE:
+      delegate->RevertWithoutClosingInfobar();
+      infobar->set_accepted(false);
+      break;
+    case translate::TranslateStep::TRANSLATE_STEP_TRANSLATING:
+    case translate::TranslateStep::TRANSLATE_STEP_NEVER_TRANSLATE:
+    case translate::TranslateStep::TRANSLATE_STEP_TRANSLATE_ERROR:
+      NOTREACHED() << "Should not be presenting Banner in this TranslateStep";
+  }
+}
+
+#pragma mark - Private
+
+translate::TranslateInfoBarDelegate*
+TranslateInfobarBannerInteractionHandler::GetInfobarDelegate(
+    InfoBarIOS* infobar) {
+  translate::TranslateInfoBarDelegate* delegate =
+      infobar->delegate()->AsTranslateInfoBarDelegate();
+  DCHECK(delegate);
+  return delegate;
+}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_banner_interaction_handler_unittest.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_banner_interaction_handler_unittest.mm
new file mode 100644
index 0000000..5edfd00
--- /dev/null
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_banner_interaction_handler_unittest.mm
@@ -0,0 +1,59 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_banner_interaction_handler.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "components/infobars/core/infobar_feature.h"
+#include "components/translate/core/browser/mock_translate_infobar_delegate.h"
+#include "ios/chrome/browser/infobars/infobar_ios.h"
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_banner_interaction_handler.h"
+#import "ios/chrome/browser/ui/infobars/infobar_feature.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// Test fixture for TranslateInfobarBannerInteractionHandler.
+class TranslateInfobarBannerInteractionHandlerTest : public PlatformTest {
+ public:
+  TranslateInfobarBannerInteractionHandlerTest()
+      : handler_(), delegate_factory_("fr", "en") {
+    scoped_feature_list_.InitWithFeatures(
+        {kIOSInfobarUIReboot, kTranslateInfobarMessagesUI}, {});
+  }
+
+  translate::testing::MockTranslateInfoBarDelegate& GetMockDelegate(
+      InfoBarIOS* infobar) {
+    return *static_cast<translate::testing::MockTranslateInfoBarDelegate*>(
+        infobar->delegate());
+  }
+
+ protected:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  TranslateInfobarBannerInteractionHandler handler_;
+  translate::testing::MockTranslateInfoBarDelegateFactory delegate_factory_;
+};
+
+// Tests MainButtonTapped() calls Translate() on the mock delegate.
+TEST_F(TranslateInfobarBannerInteractionHandlerTest, MainButton) {
+  std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>(
+      InfobarType::kInfobarTypeTranslate,
+      delegate_factory_.CreateMockTranslateInfoBarDelegate(
+          translate::TranslateStep::TRANSLATE_STEP_BEFORE_TRANSLATE));
+  EXPECT_CALL(GetMockDelegate(infobar.get()), Translate());
+  handler_.MainButtonTapped(infobar.get());
+}
+
+// Tests MainButtonTapped() calls RevertWithoutClosingInfobar() on the mock
+// delegate.
+TEST_F(TranslateInfobarBannerInteractionHandlerTest, MainButtonRevert) {
+  std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>(
+      InfobarType::kInfobarTypeTranslate,
+      delegate_factory_.CreateMockTranslateInfoBarDelegate(
+          translate::TranslateStep::TRANSLATE_STEP_AFTER_TRANSLATE));
+  EXPECT_CALL(GetMockDelegate(infobar.get()), RevertWithoutClosingInfobar());
+  handler_.MainButtonTapped(infobar.get());
+}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_interaction_handler.h
new file mode 100644
index 0000000..7c93c4b0
--- /dev/null
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_interaction_handler.h
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TRANSLATE_TRANSLATE_INFOBAR_INTERACTION_HANDLER_H_
+#define IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TRANSLATE_TRANSLATE_INFOBAR_INTERACTION_HANDLER_H_
+
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/infobar_interaction_handler.h"
+
+// An InfobarInteractionHandler that updates the model layer for interaction
+// events with the UI for Translate infobars.
+class TranslateInfobarInteractionHandler : public InfobarInteractionHandler {
+ public:
+  TranslateInfobarInteractionHandler();
+  ~TranslateInfobarInteractionHandler() override;
+};
+
+#endif  // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TRANSLATE_TRANSLATE_INFOBAR_INTERACTION_HANDLER_H_
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_interaction_handler.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_interaction_handler.mm
new file mode 100644
index 0000000..9dd545f
--- /dev/null
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_interaction_handler.mm
@@ -0,0 +1,28 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_interaction_handler.h"
+
+#include "components/infobars/core/infobar.h"
+#import "ios/chrome/browser/infobars/infobar_ios.h"
+#include "ios/chrome/browser/infobars/infobar_manager_impl.h"
+#import "ios/chrome/browser/infobars/infobar_type.h"
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_banner_interaction_handler.h"
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.h"
+#import "ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter.h"
+#import "ios/chrome/browser/main/browser.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+TranslateInfobarInteractionHandler::TranslateInfobarInteractionHandler()
+    : InfobarInteractionHandler(
+          InfobarType::kInfobarTypeTranslate,
+          std::make_unique<TranslateInfobarBannerInteractionHandler>(),
+          /*sheet_handler=*/nullptr,
+          std::make_unique<TranslateInfobarModalInteractionHandler>()) {}
+
+TranslateInfobarInteractionHandler::~TranslateInfobarInteractionHandler() =
+    default;
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.h
new file mode 100644
index 0000000..2cad065
--- /dev/null
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.h
@@ -0,0 +1,61 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TRANSLATE_TRANSLATE_INFOBAR_MODAL_INTERACTION_HANDLER_H_
+#define IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TRANSLATE_TRANSLATE_INFOBAR_MODAL_INTERACTION_HANDLER_H_
+
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_modal_interaction_handler.h"
+
+namespace translate {
+class TranslateInfoBarDelegate;
+}
+
+// Helper object that updates the model layer for interaction events with the
+// Translate infobar modal UI.
+class TranslateInfobarModalInteractionHandler
+    : public InfobarModalInteractionHandler {
+ public:
+  TranslateInfobarModalInteractionHandler();
+  ~TranslateInfobarModalInteractionHandler() override;
+
+  // Instructs the handler that the user has used |infobar|'s modal UI to
+  // request that the always translate preference be toggled.
+  virtual void ToggleAlwaysTranslate(InfoBarIOS* infobar);
+  // Instructs the handler that the user has used |infobar|'s modal UI to
+  // request that the never translate source language preference be toggled.
+  virtual void ToggleNeverTranslateLanguage(InfoBarIOS* infobar);
+  // Instructs the handler that the user has used |infobar|'s modal UI to
+  // request that the never translate site preference be toggled.
+  virtual void ToggleNeverTranslateSite(InfoBarIOS* infobar);
+  // Instructs the handler that the user has used |infobar|'s modal UI to
+  // request that the translation be reverted.
+  virtual void RevertTranslation(InfoBarIOS* infobar);
+  // Instructs the handler that the user has used |infobar|'s modal UI to
+  // request that the source language change to the language at
+  // |source_language_index| and/or the target language change to the language
+  // at |target_language_index|. If either do not need to be updated, then the
+  // index passed should be -1.
+  virtual void UpdateLanguages(InfoBarIOS* infobar,
+                               int source_language_index,
+                               int target_language_index);
+
+  // InfobarModalInteractionHandler:
+  void PerformMainAction(InfoBarIOS* infobar) override;
+
+  // InfobarInteractionHandler::Handler:
+  void InfobarVisibilityChanged(InfoBarIOS* infobar, bool visible) override;
+
+ private:
+  // Initiates a translate for |infobar|.
+  void StartTranslation(InfoBarIOS* infobar);
+
+  // InfobarModalInteractionHandler:
+  std::unique_ptr<InfobarModalOverlayRequestCallbackInstaller>
+  CreateModalInstaller() override;
+
+  // Returns the translate delegate from |infobar|.
+  translate::TranslateInfoBarDelegate* GetDelegate(InfoBarIOS* infobar);
+};
+
+#endif  // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TRANSLATE_TRANSLATE_INFOBAR_MODAL_INTERACTION_HANDLER_H_
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.mm
new file mode 100644
index 0000000..fbe776a
--- /dev/null
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.mm
@@ -0,0 +1,127 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.h"
+
+#include "components/translate/core/browser/translate_infobar_delegate.h"
+#include "ios/chrome/browser/infobars/infobar_ios.h"
+#include "ios/chrome/browser/infobars/infobar_manager_impl.h"
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_overlay_request_callback_installer.h"
+#import "ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter.h"
+#include "ios/chrome/browser/infobars/overlays/infobar_overlay_util.h"
+#import "ios/chrome/browser/infobars/overlays/translate_infobar_placeholder_overlay_request_cancel_handler.h"
+#import "ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper.h"
+#import "ios/chrome/browser/overlays/public/infobar_banner/infobar_banner_placeholder_request_config.h"
+#import "ios/chrome/browser/overlays/public/infobar_banner/translate_infobar_banner_overlay_request_config.h"
+#import "ios/chrome/browser/overlays/public/overlay_request_queue.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+using translate_infobar_overlays::TranslateBannerRequestConfig;
+using translate_infobar_overlays::PlaceholderRequestCancelHandler;
+using translate_infobar_overlay::ModalRequestCallbackInstaller;
+
+TranslateInfobarModalInteractionHandler::
+    TranslateInfobarModalInteractionHandler() = default;
+
+TranslateInfobarModalInteractionHandler::
+    ~TranslateInfobarModalInteractionHandler() = default;
+
+#pragma mark - Public
+
+void TranslateInfobarModalInteractionHandler::ToggleAlwaysTranslate(
+    InfoBarIOS* infobar) {
+  translate::TranslateInfoBarDelegate* delegate = GetDelegate(infobar);
+  bool enabling_always_translate = !delegate->ShouldAlwaysTranslate();
+  delegate->ToggleAlwaysTranslate();
+  if (enabling_always_translate) {
+    StartTranslation(infobar);
+  }
+}
+
+void TranslateInfobarModalInteractionHandler::ToggleNeverTranslateLanguage(
+    InfoBarIOS* infobar) {
+  translate::TranslateInfoBarDelegate* delegate = GetDelegate(infobar);
+  bool should_remove_infobar = delegate->IsTranslatableLanguageByPrefs();
+  delegate->ToggleTranslatableLanguageByPrefs();
+  // Remove infobar if turning it on.
+  if (should_remove_infobar)
+    infobar->RemoveSelf();
+}
+
+void TranslateInfobarModalInteractionHandler::ToggleNeverTranslateSite(
+    InfoBarIOS* infobar) {
+  translate::TranslateInfoBarDelegate* delegate = GetDelegate(infobar);
+  bool should_remove_infobar = !delegate->IsSiteBlacklisted();
+  delegate->ToggleSiteBlacklist();
+  // Remove infobar if turning it on.
+  if (should_remove_infobar)
+    infobar->RemoveSelf();
+}
+
+void TranslateInfobarModalInteractionHandler::RevertTranslation(
+    InfoBarIOS* infobar) {
+  GetDelegate(infobar)->RevertWithoutClosingInfobar();
+  infobar->set_accepted(false);
+}
+
+void TranslateInfobarModalInteractionHandler::UpdateLanguages(
+    InfoBarIOS* infobar,
+    int source_language_index,
+    int target_language_index) {
+  translate::TranslateInfoBarDelegate* delegate = GetDelegate(infobar);
+  if (source_language_index != -1) {
+    std::string source_language_code =
+        delegate->language_code_at(source_language_index);
+    if (delegate->original_language_code() != source_language_code) {
+      delegate->UpdateOriginalLanguage(source_language_code);
+    }
+  }
+
+  if (target_language_index != -1) {
+    std::string target_language_code =
+        delegate->language_code_at(target_language_index);
+    if (delegate->target_language_code() != target_language_code) {
+      delegate->UpdateTargetLanguage(target_language_code);
+    }
+  }
+}
+
+#pragma mark - InfobarInteractionHandler::Handler
+
+void TranslateInfobarModalInteractionHandler::InfobarVisibilityChanged(
+    InfoBarIOS* infobar,
+    bool visible) {
+  if (!visible)
+    GetDelegate(infobar)->InfoBarDismissed();
+}
+
+#pragma mark - InfobarModalInteractionHandler
+
+void TranslateInfobarModalInteractionHandler::PerformMainAction(
+    InfoBarIOS* infobar) {
+  StartTranslation(infobar);
+}
+
+#pragma mark - Private
+
+void TranslateInfobarModalInteractionHandler::StartTranslation(
+    InfoBarIOS* infobar) {
+  GetDelegate(infobar)->Translate();
+}
+
+std::unique_ptr<InfobarModalOverlayRequestCallbackInstaller>
+TranslateInfobarModalInteractionHandler::CreateModalInstaller() {
+  return std::make_unique<ModalRequestCallbackInstaller>(this);
+}
+
+translate::TranslateInfoBarDelegate*
+TranslateInfobarModalInteractionHandler::GetDelegate(InfoBarIOS* infobar) {
+  translate::TranslateInfoBarDelegate* delegate =
+      infobar->delegate()->AsTranslateInfoBarDelegate();
+  DCHECK(delegate);
+  return delegate;
+}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler_unittest.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler_unittest.mm
new file mode 100644
index 0000000..c8d8e188
--- /dev/null
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler_unittest.mm
@@ -0,0 +1,100 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "components/infobars/core/infobar_feature.h"
+#include "components/translate/core/browser/mock_translate_infobar_delegate.h"
+#include "ios/chrome/browser/infobars/infobar_ios.h"
+#import "ios/chrome/browser/infobars/test/fake_infobar_ios.h"
+#import "ios/chrome/browser/ui/infobars/infobar_feature.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// Test fixture for TranslateInfobarModalInteractionHandler.
+class TranslateInfobarModalInteractionHandlerTest : public PlatformTest {
+ public:
+  TranslateInfobarModalInteractionHandlerTest()
+      : handler_(), delegate_factory_("fr", "en") {
+    scoped_feature_list_.InitWithFeatures(
+        {kIOSInfobarUIReboot, kTranslateInfobarMessagesUI}, {});
+  }
+
+  translate::testing::MockTranslateInfoBarDelegate& mock_delegate(
+      InfoBarIOS* infobar) {
+    return *static_cast<translate::testing::MockTranslateInfoBarDelegate*>(
+        infobar->delegate());
+  }
+
+ protected:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  TranslateInfobarModalInteractionHandler handler_;
+  translate::testing::MockTranslateInfoBarDelegateFactory delegate_factory_;
+};
+
+TEST_F(TranslateInfobarModalInteractionHandlerTest, MainButton) {
+  std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>(
+      InfobarType::kInfobarTypeTranslate,
+      delegate_factory_.CreateMockTranslateInfoBarDelegate(
+          translate::TranslateStep::TRANSLATE_STEP_BEFORE_TRANSLATE));
+  EXPECT_CALL(mock_delegate(infobar.get()), Translate());
+  handler_.PerformMainAction(infobar.get());
+}
+
+TEST_F(TranslateInfobarModalInteractionHandlerTest, ToggleAlwaysTranslate) {
+  std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>(
+      InfobarType::kInfobarTypeTranslate,
+      delegate_factory_.CreateMockTranslateInfoBarDelegate(
+          translate::TranslateStep::TRANSLATE_STEP_BEFORE_TRANSLATE));
+  EXPECT_CALL(mock_delegate(infobar.get()), Translate());
+  EXPECT_CALL(mock_delegate(infobar.get()), ToggleAlwaysTranslate());
+  handler_.ToggleAlwaysTranslate(infobar.get());
+}
+
+TEST_F(TranslateInfobarModalInteractionHandlerTest,
+       ToggleNeverTranslateLanguage) {
+  std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>(
+      InfobarType::kInfobarTypeTranslate,
+      delegate_factory_.CreateMockTranslateInfoBarDelegate(
+          translate::TranslateStep::TRANSLATE_STEP_BEFORE_TRANSLATE));
+  EXPECT_CALL(mock_delegate(infobar.get()),
+              ToggleTranslatableLanguageByPrefs());
+  handler_.ToggleNeverTranslateLanguage(infobar.get());
+}
+
+TEST_F(TranslateInfobarModalInteractionHandlerTest, ToggleNeverTranslateSite) {
+  std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>(
+      InfobarType::kInfobarTypeTranslate,
+      delegate_factory_.CreateMockTranslateInfoBarDelegate(
+          translate::TranslateStep::TRANSLATE_STEP_BEFORE_TRANSLATE));
+  EXPECT_CALL(mock_delegate(infobar.get()), ToggleSiteBlacklist());
+  handler_.ToggleNeverTranslateSite(infobar.get());
+}
+
+TEST_F(TranslateInfobarModalInteractionHandlerTest, RevertTranslation) {
+  std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>(
+      InfobarType::kInfobarTypeTranslate,
+      delegate_factory_.CreateMockTranslateInfoBarDelegate(
+          translate::TranslateStep::TRANSLATE_STEP_BEFORE_TRANSLATE));
+  EXPECT_CALL(mock_delegate(infobar.get()), RevertWithoutClosingInfobar());
+  handler_.RevertTranslation(infobar.get());
+}
+
+TEST_F(TranslateInfobarModalInteractionHandlerTest, UpdateLanguages) {
+  std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>(
+      InfobarType::kInfobarTypeTranslate,
+      delegate_factory_.CreateMockTranslateInfoBarDelegate(
+          translate::TranslateStep::TRANSLATE_STEP_BEFORE_TRANSLATE));
+  int source_index = 0;
+  int target_index = 1;
+  // Just assert that the methods are called. The actual codes are unecessary to
+  // mock since it is dependent on the Translate model.
+  EXPECT_CALL(mock_delegate(infobar.get()), UpdateTargetLanguage(_));
+  EXPECT_CALL(mock_delegate(infobar.get()), UpdateOriginalLanguage(_));
+  handler_.UpdateLanguages(infobar.get(), source_index, target_index);
+}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_overlay_request_callback_installer.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_overlay_request_callback_installer.h
new file mode 100644
index 0000000..8a9006b
--- /dev/null
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_overlay_request_callback_installer.h
@@ -0,0 +1,72 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TRANSLATE_TRANSLATE_INFOBAR_MODAL_OVERLAY_REQUEST_CALLBACK_INSTALLER_H_
+#define IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TRANSLATE_TRANSLATE_INFOBAR_MODAL_OVERLAY_REQUEST_CALLBACK_INSTALLER_H_
+
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_modal_overlay_request_callback_installer.h"
+
+#include "base/memory/weak_ptr.h"
+
+class TranslateInfobarModalInteractionHandler;
+
+namespace translate_infobar_overlay {
+
+// Callback installer, intended to be subclassed, for infobar modal interaction
+// events.
+class ModalRequestCallbackInstaller
+    : public InfobarModalOverlayRequestCallbackInstaller {
+ public:
+  // Constructor for an instance that installs callbacks that forward
+  // interaction events to |interaction_handler|.
+  explicit ModalRequestCallbackInstaller(
+      TranslateInfobarModalInteractionHandler* interaction_handler);
+  ~ModalRequestCallbackInstaller() override;
+
+ private:
+  // Used as a callback for OverlayResponses dispatched through |request|'s
+  // callback manager. The OverlayDispatchCallback is created with an
+  // OverlayResponseSupport that guarantees that |response| is created with an
+  // translate_infobar_modal_responses::RevertMainAction.
+  void RevertTranslationCallback(OverlayRequest* request,
+                                 OverlayResponse* response);
+
+  // Used as a callback for OverlayResponses dispatched through |request|'s
+  // callback manager. The OverlayDispatchCallback is created with an
+  // OverlayResponseSupport that guarantees that |response| is created with an
+  // translate_infobar_modal_responses::ToggleAlwaysTranslate.
+  void ToggleAlwaysTranslateCallback(OverlayRequest* request,
+                                     OverlayResponse* response);
+  // Used as a callback for OverlayResponses dispatched through |request|'s
+  // callback manager. The OverlayDispatchCallback is created with an
+  // OverlayResponseSupport that guarantees that |response| is created with a
+  // translate_infobar_modal_responses::ToggleNeverTranslateSourceLanguage.
+  void ToggleNeverTranslateSourceLanguageCallback(OverlayRequest* request,
+                                                  OverlayResponse* response);
+  // Used as a callback for OverlayResponses dispatched through |request|'s
+  // callback manager. The OverlayDispatchCallback is created with an
+  // OverlayResponseSupport that guarantees that |response| is created with a
+  // translate_infobar_modal_responses::ToggleBlacklistSite.
+  void ToggleNeverTranslateSiteCallback(OverlayRequest* request,
+                                        OverlayResponse* response);
+
+  // Used as a callback for OverlayResponses dispatched through |request|'s
+  // callback manager. The OverlayDispatchCallback is created with an
+  // OverlayResponseSupport that guarantees that |response| is created with a
+  // translate_infobar_modal_responses::UpdateLanguageInfo.
+  void UpdateLanguageCallback(OverlayRequest* request,
+                              OverlayResponse* response);
+
+  // OverlayRequestCallbackInstaller:
+  void InstallCallbacksInternal(OverlayRequest* request) override;
+
+  // The handler for received responses.
+  TranslateInfobarModalInteractionHandler* interaction_handler_ = nullptr;
+
+  base::WeakPtrFactory<ModalRequestCallbackInstaller> weak_factory_{this};
+};
+
+}  // namespace translate_infobar_overlay
+
+#endif  // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TRANSLATE_TRANSLATE_INFOBAR_MODAL_OVERLAY_REQUEST_CALLBACK_INSTALLER_H_
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_overlay_request_callback_installer.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_overlay_request_callback_installer.mm
new file mode 100644
index 0000000..4eb79a6
--- /dev/null
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_overlay_request_callback_installer.mm
@@ -0,0 +1,129 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_overlay_request_callback_installer.h"
+
+#include "base/bind.h"
+#include "ios/chrome/browser/infobars/infobar_ios.h"
+#include "ios/chrome/browser/infobars/infobar_manager_impl.h"
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.h"
+#include "ios/chrome/browser/infobars/overlays/infobar_overlay_util.h"
+#import "ios/chrome/browser/overlays/public/infobar_modal/translate_infobar_modal_overlay_request_config.h"
+#import "ios/chrome/browser/overlays/public/infobar_modal/translate_infobar_modal_overlay_responses.h"
+#include "ios/chrome/browser/overlays/public/overlay_callback_manager.h"
+#import "ios/chrome/browser/overlays/public/overlay_response.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+using translate_infobar_overlays::TranslateModalRequestConfig;
+using translate_infobar_modal_responses::RevertTranslation;
+using translate_infobar_modal_responses::ToggleAlwaysTranslate;
+using translate_infobar_modal_responses::ToggleNeverTranslateSourceLanguage;
+using translate_infobar_modal_responses::ToggleBlacklistSite;
+using translate_infobar_modal_responses::UpdateLanguageInfo;
+
+namespace translate_infobar_overlay {
+
+ModalRequestCallbackInstaller::ModalRequestCallbackInstaller(
+    TranslateInfobarModalInteractionHandler* interaction_handler)
+    : InfobarModalOverlayRequestCallbackInstaller(
+          TranslateModalRequestConfig::RequestSupport(),
+          interaction_handler),
+      interaction_handler_(interaction_handler) {
+  DCHECK(interaction_handler_);
+}
+
+ModalRequestCallbackInstaller::~ModalRequestCallbackInstaller() = default;
+
+#pragma mark - Private
+
+void ModalRequestCallbackInstaller::RevertTranslationCallback(
+    OverlayRequest* request,
+    OverlayResponse* response) {
+  InfoBarIOS* infobar = GetOverlayRequestInfobar(request);
+  if (!infobar)
+    return;
+
+  interaction_handler_->RevertTranslation(infobar);
+}
+
+void ModalRequestCallbackInstaller::ToggleAlwaysTranslateCallback(
+    OverlayRequest* request,
+    OverlayResponse* response) {
+  InfoBarIOS* infobar = GetOverlayRequestInfobar(request);
+  if (!infobar)
+    return;
+
+  interaction_handler_->ToggleAlwaysTranslate(infobar);
+}
+
+void ModalRequestCallbackInstaller::ToggleNeverTranslateSourceLanguageCallback(
+    OverlayRequest* request,
+    OverlayResponse* response) {
+  InfoBarIOS* infobar = GetOverlayRequestInfobar(request);
+  if (!infobar)
+    return;
+  interaction_handler_->ToggleNeverTranslateLanguage(infobar);
+}
+
+void ModalRequestCallbackInstaller::ToggleNeverTranslateSiteCallback(
+    OverlayRequest* request,
+    OverlayResponse* response) {
+  InfoBarIOS* infobar = GetOverlayRequestInfobar(request);
+  if (!infobar)
+    return;
+  interaction_handler_->ToggleNeverTranslateSite(infobar);
+}
+
+void ModalRequestCallbackInstaller::UpdateLanguageCallback(
+    OverlayRequest* request,
+    OverlayResponse* response) {
+  InfoBarIOS* infobar = GetOverlayRequestInfobar(request);
+  if (!infobar)
+    return;
+  UpdateLanguageInfo* response_info = response->GetInfo<UpdateLanguageInfo>();
+
+  interaction_handler_->UpdateLanguages(infobar,
+                                        response_info->source_language_index(),
+                                        response_info->target_language_index());
+}
+
+#pragma mark - OverlayRequestCallbackInstaller
+
+void ModalRequestCallbackInstaller::InstallCallbacksInternal(
+    OverlayRequest* request) {
+  InfobarModalOverlayRequestCallbackInstaller::InstallCallbacksInternal(
+      request);
+  OverlayCallbackManager* manager = request->GetCallbackManager();
+
+  manager->AddDispatchCallback(OverlayDispatchCallback(
+      base::BindRepeating(
+          &ModalRequestCallbackInstaller::RevertTranslationCallback,
+          weak_factory_.GetWeakPtr(), request),
+      RevertTranslation::ResponseSupport()));
+  manager->AddDispatchCallback(OverlayDispatchCallback(
+      base::BindRepeating(
+          &ModalRequestCallbackInstaller::ToggleAlwaysTranslateCallback,
+          weak_factory_.GetWeakPtr(), request),
+      ToggleAlwaysTranslate::ResponseSupport()));
+  manager->AddDispatchCallback(OverlayDispatchCallback(
+      base::BindRepeating(&ModalRequestCallbackInstaller::
+                              ToggleNeverTranslateSourceLanguageCallback,
+                          weak_factory_.GetWeakPtr(), request),
+      ToggleNeverTranslateSourceLanguage::ResponseSupport()));
+  manager->AddDispatchCallback(OverlayDispatchCallback(
+      base::BindRepeating(
+          &ModalRequestCallbackInstaller::ToggleNeverTranslateSiteCallback,
+          weak_factory_.GetWeakPtr(), request),
+      ToggleBlacklistSite::ResponseSupport()));
+  manager->AddDispatchCallback(OverlayDispatchCallback(
+      base::BindRepeating(
+          &ModalRequestCallbackInstaller::UpdateLanguageCallback,
+          weak_factory_.GetWeakPtr(), request),
+      UpdateLanguageInfo::ResponseSupport()));
+}
+
+}  // namespace translate_infobar_overlay
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_overlay_request_callback_installer_unittest.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_overlay_request_callback_installer_unittest.mm
new file mode 100644
index 0000000..d4a5665
--- /dev/null
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_overlay_request_callback_installer_unittest.mm
@@ -0,0 +1,137 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_overlay_request_callback_installer.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "components/infobars/core/infobar_feature.h"
+#include "components/translate/core/browser/mock_translate_infobar_delegate.h"
+#include "ios/chrome/browser/infobars/infobar_ios.h"
+#include "ios/chrome/browser/infobars/infobar_manager_impl.h"
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_translate_infobar_interaction_handler.h"
+#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate/translate_infobar_modal_interaction_handler.h"
+#import "ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper.h"
+#import "ios/chrome/browser/overlays/public/infobar_modal/infobar_modal_overlay_responses.h"
+#import "ios/chrome/browser/overlays/public/infobar_modal/translate_infobar_modal_overlay_request_config.h"
+#import "ios/chrome/browser/overlays/public/infobar_modal/translate_infobar_modal_overlay_responses.h"
+#include "ios/chrome/browser/overlays/public/overlay_callback_manager.h"
+#include "ios/chrome/browser/overlays/public/overlay_request.h"
+#include "ios/chrome/browser/overlays/public/overlay_request_queue.h"
+#include "ios/chrome/browser/overlays/public/overlay_response.h"
+#import "ios/chrome/browser/ui/infobars/infobar_feature.h"
+#import "ios/web/public/test/fakes/test_navigation_manager.h"
+#import "ios/web/public/test/fakes/test_web_state.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+using translate::testing::MockTranslateInfoBarDelegate;
+
+// Test fixture for TranslateInfobarModalOverlayRequestCallbackInstaller.
+class TranslateInfobarModalOverlayRequestCallbackInstallerTest
+    : public PlatformTest {
+ public:
+  TranslateInfobarModalOverlayRequestCallbackInstallerTest()
+      : installer_(&mock_handler_), delegate_factory_("fr", "en") {
+    scoped_feature_list_.InitWithFeatures({kIOSInfobarUIReboot},
+                                          {kInfobarUIRebootOnlyiOS13});
+    // Create the infobar and add it to the WebState's manager.
+    web_state_.SetNavigationManager(
+        std::make_unique<web::TestNavigationManager>());
+    InfoBarManagerImpl::CreateForWebState(&web_state_);
+    TranslateOverlayTabHelper::CreateForWebState(&web_state_);
+    std::unique_ptr<MockTranslateInfoBarDelegate> delegate =
+        delegate_factory_.CreateMockTranslateInfoBarDelegate(
+            translate::TranslateStep::TRANSLATE_STEP_BEFORE_TRANSLATE);
+    delegate_ = delegate.get();
+    std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>(
+        InfobarType::kInfobarTypeTranslate, std::move(delegate));
+
+    infobar_ = infobar.get();
+    manager()->AddInfoBar(std::move(infobar));
+    // Create the request and add it to the WebState's queue.
+    std::unique_ptr<OverlayRequest> added_request =
+        OverlayRequest::CreateWithConfig<
+            translate_infobar_overlays::TranslateModalRequestConfig>(infobar_);
+    request_ = added_request.get();
+    queue()->AddRequest(std::move(added_request));
+    // Install the callbacks on the added request.
+    installer_.InstallCallbacks(request_);
+  }
+
+  InfoBarManagerImpl* manager() {
+    return InfoBarManagerImpl::FromWebState(&web_state_);
+  }
+  OverlayRequestQueue* queue() {
+    return OverlayRequestQueue::FromWebState(&web_state_,
+                                             OverlayModality::kInfobarModal);
+  }
+
+ protected:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  web::TestWebState web_state_;
+  InfoBarIOS* infobar_ = nullptr;
+  OverlayRequest* request_ = nullptr;
+  MockTranslateInfobarModalInteractionHandler mock_handler_;
+  translate_infobar_overlay::ModalRequestCallbackInstaller installer_;
+  translate::testing::MockTranslateInfoBarDelegateFactory delegate_factory_;
+  translate::testing::MockTranslateInfoBarDelegate* delegate_;
+};
+
+TEST_F(TranslateInfobarModalOverlayRequestCallbackInstallerTest,
+       UpdateLanguages) {
+  int source_language_index = 0;
+  int target_language_index = 1;
+  // Just assert that the methods are called. The actual codes are unecessary to
+  // mock since it is dependent on the Translate model.
+  EXPECT_CALL(mock_handler_, UpdateLanguages(infobar_, source_language_index,
+                                             target_language_index));
+  request_->GetCallbackManager()->DispatchResponse(
+      OverlayResponse::CreateWithInfo<
+          translate_infobar_modal_responses::UpdateLanguageInfo>(
+          source_language_index, target_language_index));
+}
+
+TEST_F(TranslateInfobarModalOverlayRequestCallbackInstallerTest,
+       ToggleAlwaysTranslate) {
+  EXPECT_CALL(mock_handler_, ToggleAlwaysTranslate(infobar_));
+  request_->GetCallbackManager()->DispatchResponse(
+      OverlayResponse::CreateWithInfo<
+          translate_infobar_modal_responses::ToggleAlwaysTranslate>());
+}
+
+TEST_F(TranslateInfobarModalOverlayRequestCallbackInstallerTest,
+       RevertTranslation) {
+  EXPECT_CALL(mock_handler_, RevertTranslation(infobar_));
+  request_->GetCallbackManager()->DispatchResponse(
+      OverlayResponse::CreateWithInfo<
+          translate_infobar_modal_responses::RevertTranslation>());
+}
+
+TEST_F(TranslateInfobarModalOverlayRequestCallbackInstallerTest,
+       ToggleNeverTranslateSite) {
+  EXPECT_CALL(mock_handler_, ToggleNeverTranslateSite(infobar_));
+  request_->GetCallbackManager()->DispatchResponse(
+      OverlayResponse::CreateWithInfo<
+          translate_infobar_modal_responses::ToggleBlacklistSite>());
+}
+
+TEST_F(TranslateInfobarModalOverlayRequestCallbackInstallerTest,
+       ToggleNeverTranslateLanguage) {
+  EXPECT_CALL(mock_handler_, ToggleNeverTranslateLanguage(infobar_));
+  request_->GetCallbackManager()->DispatchResponse(
+      OverlayResponse::CreateWithInfo<
+          translate_infobar_modal_responses::
+              ToggleNeverTranslateSourceLanguage>());
+}
+
+TEST_F(TranslateInfobarModalOverlayRequestCallbackInstallerTest,
+       PerformMainAction) {
+  EXPECT_CALL(mock_handler_, PerformMainAction(infobar_));
+  request_->GetCallbackManager()->DispatchResponse(
+      OverlayResponse::CreateWithInfo<InfobarModalMainActionResponse>());
+}
diff --git a/ios/chrome/browser/overlays/overlay_browser_agent_base.mm b/ios/chrome/browser/overlays/overlay_browser_agent_base.mm
index c890ba3a..ae29fd6 100644
--- a/ios/chrome/browser/overlays/overlay_browser_agent_base.mm
+++ b/ios/chrome/browser/overlays/overlay_browser_agent_base.mm
@@ -94,7 +94,10 @@
 
 void OverlayBrowserAgentBase::CallbackInstallationDriver::WillShowOverlay(
     OverlayPresenter* presenter,
-    OverlayRequest* request) {
+    OverlayRequest* request,
+    bool initial_presentation) {
+  if (!initial_presentation)
+    return;
   browser_agent_->InstallOverlayRequestCallbacks(request,
                                                  presenter->GetModality());
 }
diff --git a/ios/chrome/browser/overlays/overlay_presenter_impl.h b/ios/chrome/browser/overlays/overlay_presenter_impl.h
index bd7fa2f..aae72851 100644
--- a/ios/chrome/browser/overlays/overlay_presenter_impl.h
+++ b/ios/chrome/browser/overlays/overlay_presenter_impl.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_OVERLAYS_OVERLAY_PRESENTER_IMPL_H_
 #define IOS_CHROME_BROWSER_OVERLAYS_OVERLAY_PRESENTER_IMPL_H_
 
+#include <set>
+
 #include "base/memory/weak_ptr.h"
 #import "ios/chrome/browser/main/browser_observer.h"
 #import "ios/chrome/browser/overlays/overlay_request_queue_impl.h"
@@ -15,6 +17,8 @@
 #import "ios/chrome/browser/overlays/public/overlay_user_data.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer.h"
 
+class OverlayResponse;
+
 // Implementation of OverlayPresenter.  The presenter:
 // - observes OverlayRequestQueue modifications for the active WebState and
 //   triggers the presentation for added requests using the UI delegate.
@@ -98,6 +102,10 @@
                            base::WeakPtr<OverlayRequestQueueImpl> queue,
                            OverlayDismissalReason reason);
 
+  // Used as a completion callback for |request|.  Cleans up state associated
+  // with |request|.
+  void OverlayWasCompleted(OverlayRequest* request, OverlayResponse* response);
+
   // Cancels all overlays for |request|.
   void CancelOverlayUIForRequest(OverlayRequest* request);
 
@@ -178,6 +186,9 @@
   // Used to extend the lifetime of an OverlayRequest after being removed from
   // a queue until the completion of its dismissal flow.
   std::unique_ptr<OverlayRequest> removed_request_awaiting_dismissal_;
+  // A set of all OverlayRequests that have been shown by the presenter.
+  // Requests are removed when they are completed.
+  std::set<OverlayRequest*> previously_presented_requests_;
 
   OverlayModality modality_;
   WebStateList* web_state_list_ = nullptr;
diff --git a/ios/chrome/browser/overlays/overlay_presenter_impl.mm b/ios/chrome/browser/overlays/overlay_presenter_impl.mm
index 27fe2c3..40d15a4 100644
--- a/ios/chrome/browser/overlays/overlay_presenter_impl.mm
+++ b/ios/chrome/browser/overlays/overlay_presenter_impl.mm
@@ -7,6 +7,7 @@
 #include "base/check_op.h"
 #include "base/memory/ptr_util.h"
 #import "ios/chrome/browser/main/browser.h"
+#include "ios/chrome/browser/overlays/public/overlay_callback_manager.h"
 #import "ios/chrome/browser/overlays/public/overlay_presentation_context.h"
 #import "ios/chrome/browser/overlays/public/overlay_presenter_observer.h"
 #include "ios/chrome/browser/overlays/public/overlay_request.h"
@@ -100,6 +101,7 @@
   // delegate's presentation context.
   presenting_ = false;
   presented_request_ = nullptr;
+  previously_presented_requests_.clear();
 
   if (presentation_context_) {
     presentation_context_->AddObserver(this);
@@ -217,11 +219,20 @@
   presented_request_ = request;
 
   // Notify the observers that the overlay UI is about to be shown.
+  bool initial_presentation = previously_presented_requests_.find(request) ==
+                              previously_presented_requests_.end();
   for (auto& observer : observers_) {
     if (observer.GetRequestSupport(this)->IsRequestSupported(request))
-      observer.WillShowOverlay(this, request);
+      observer.WillShowOverlay(this, request, initial_presentation);
   }
 
+  // Record that the request was shown, and add the completion callback to
+  // remove the request from the set.
+  previously_presented_requests_.insert(request);
+  request->GetCallbackManager()->AddCompletionCallback(
+      base::BindOnce(&OverlayPresenterImpl::OverlayWasCompleted,
+                     weak_factory_.GetWeakPtr(), request));
+
   // Present the overlay UI via the UI delegate.
   OverlayPresentationCallback presentation_callback = base::BindOnce(
       &OverlayPresenterImpl::OverlayWasPresented, weak_factory_.GetWeakPtr(),
@@ -313,6 +324,11 @@
     PresentOverlayForActiveRequest();
 }
 
+void OverlayPresenterImpl::OverlayWasCompleted(OverlayRequest* request,
+                                               OverlayResponse* response) {
+  previously_presented_requests_.erase(request);
+}
+
 #pragma mark UI Cancellation helpers
 
 void OverlayPresenterImpl::CancelOverlayUIForRequest(OverlayRequest* request) {
diff --git a/ios/chrome/browser/overlays/overlay_presenter_impl_unittest.mm b/ios/chrome/browser/overlays/overlay_presenter_impl_unittest.mm
index 6762f60..c800595 100644
--- a/ios/chrome/browser/overlays/overlay_presenter_impl_unittest.mm
+++ b/ios/chrome/browser/overlays/overlay_presenter_impl_unittest.mm
@@ -32,7 +32,7 @@
   MockOverlayPresenterObserver() {}
   ~MockOverlayPresenterObserver() {}
 
-  MOCK_METHOD2(WillShowOverlay, void(OverlayPresenter*, OverlayRequest*));
+  MOCK_METHOD3(WillShowOverlay, void(OverlayPresenter*, OverlayRequest*, bool));
   MOCK_METHOD2(DidHideOverlay, void(OverlayPresenter*, OverlayRequest*));
 
   // OverlayPresenter's ObserverList checks that it is empty upon deallocation,
@@ -96,7 +96,8 @@
         OverlayRequest::CreateWithConfig<FakeOverlayUserData>();
     OverlayRequest* request = inserted_request.get();
     if (expect_presentation)
-      EXPECT_CALL(observer(), WillShowOverlay(&presenter(), request));
+      EXPECT_CALL(observer(), WillShowOverlay(&presenter(), request,
+                                              /*initial_presentation=*/true));
     GetQueueForWebState(web_state)->InsertRequest(index,
                                                   std::move(inserted_request));
     return request;
@@ -180,7 +181,8 @@
   // Dismiss |inserted_request|'s UI check that the |request|'s UI is presented
   // again.
   EXPECT_CALL(observer(), DidHideOverlay(&presenter(), inserted_request));
-  EXPECT_CALL(observer(), WillShowOverlay(&presenter(), request));
+  EXPECT_CALL(observer(), WillShowOverlay(&presenter(), request,
+                                          /*initial_presentation=*/false));
   presentation_context().SimulateDismissalForRequest(
       inserted_request, OverlayDismissalReason::kUserInteraction);
   EXPECT_EQ(FakeOverlayPresentationContext::PresentationState::kUserDismissed,
@@ -249,11 +251,12 @@
             presentation_context().GetPresentationState(request));
   ASSERT_TRUE(presenter().IsShowingOverlayUI());
 
-  // Reset the UI delegate and verify that the overlay UI is cancelled in the
-  // previous delegate's context and presented in the new delegate's context.
+  // Reset the presentation context and verify that the overlay UI is cancelled
+  // in the previous context and presented in the new context.
   FakeOverlayPresentationContext new_presentation_context;
   EXPECT_CALL(observer(), DidHideOverlay(&presenter(), request));
-  EXPECT_CALL(observer(), WillShowOverlay(&presenter(), request));
+  EXPECT_CALL(observer(), WillShowOverlay(&presenter(), request,
+                                          /*initial_presentation=*/true));
   presenter().SetPresentationContext(&new_presentation_context);
   EXPECT_EQ(FakeOverlayPresentationContext::PresentationState::kCancelled,
             presentation_context().GetPresentationState(request));
@@ -332,7 +335,8 @@
   // Reactivate the first WebState and verify that its overlay is presented
   // while the second WebState's overlay is hidden.
   EXPECT_CALL(observer(), DidHideOverlay(&presenter(), second_request));
-  EXPECT_CALL(observer(), WillShowOverlay(&presenter(), first_request));
+  EXPECT_CALL(observer(), WillShowOverlay(&presenter(), first_request,
+                                          /*initial_presentation=*/false));
   web_state_list().ActivateWebStateAt(0);
   EXPECT_EQ(FakeOverlayPresentationContext::PresentationState::kPresented,
             presentation_context().GetPresentationState(first_request));
@@ -574,7 +578,8 @@
       std::make_unique<FakeOverlayRequestCancelHandler>(request, queue);
   FakeOverlayRequestCancelHandler* cancel_handler =
       inserted_cancel_handler.get();
-  EXPECT_CALL(observer(), WillShowOverlay(&presenter(), request));
+  EXPECT_CALL(observer(), WillShowOverlay(&presenter(), request,
+                                          /*initial_presentation=*/true));
   queue->AddRequest(std::move(inserted_request));
 
   // Disable dismissal callbacks in the fake context and cancel the request.
diff --git a/ios/chrome/browser/overlays/overlay_presenter_observer_bridge.mm b/ios/chrome/browser/overlays/overlay_presenter_observer_bridge.mm
index 6d613b85..69e1f5b 100644
--- a/ios/chrome/browser/overlays/overlay_presenter_observer_bridge.mm
+++ b/ios/chrome/browser/overlays/overlay_presenter_observer_bridge.mm
@@ -30,10 +30,14 @@
 
 void OverlayPresenterObserverBridge::WillShowOverlay(
     OverlayPresenter* presenter,
-    OverlayRequest* request) {
-  if ([observer_ respondsToSelector:@selector(overlayPresenter:
-                                        willShowOverlayForRequest:)]) {
-    [observer_ overlayPresenter:presenter willShowOverlayForRequest:request];
+    OverlayRequest* request,
+    bool initial_presentation) {
+  if ([observer_ respondsToSelector:@selector
+                 (overlayPresenter:
+                     willShowOverlayForRequest:initialPresentation:)]) {
+    [observer_ overlayPresenter:presenter
+        willShowOverlayForRequest:request
+              initialPresentation:initial_presentation];
   }
 }
 
diff --git a/ios/chrome/browser/overlays/overlay_presenter_observer_bridge_unittest.mm b/ios/chrome/browser/overlays/overlay_presenter_observer_bridge_unittest.mm
index cfb216d6..2dd3e0f 100644
--- a/ios/chrome/browser/overlays/overlay_presenter_observer_bridge_unittest.mm
+++ b/ios/chrome/browser/overlays/overlay_presenter_observer_bridge_unittest.mm
@@ -33,7 +33,8 @@
 }
 
 - (void)overlayPresenter:(OverlayPresenter*)presenter
-    willShowOverlayForRequest:(OverlayRequest*)request {
+    willShowOverlayForRequest:(OverlayRequest*)request
+          initialPresentation:(BOOL)initialPresentation {
   _willShowCalled = YES;
 }
 
@@ -71,14 +72,15 @@
   std::unique_ptr<OverlayRequestSupport> support =
       std::make_unique<SupportsOverlayRequest<FakeOverlayUserData>>();
   observer_.support = support.get();
-  EXPECT_EQ(support.get(), bridge_.GetRequestSupport(nullptr));
+  EXPECT_EQ(support.get(), bridge_.GetRequestSupport(/*request=*/nullptr));
 }
 
 // Tests that OverlayPresenterObserver::WillShowOverlay() is correctly
 // forwarded.
 TEST_F(OverlayPresenterObserverBridgeTest, WillShowCalled) {
   ASSERT_FALSE(observer_.willShowCalled);
-  bridge_.WillShowOverlay(nullptr, nullptr);
+  bridge_.WillShowOverlay(/*presenter=*/nullptr, /*request=*/nullptr,
+                          /*initial_presentation=*/true);
   EXPECT_TRUE(observer_.willShowCalled);
 }
 
@@ -86,7 +88,7 @@
 // forwarded.
 TEST_F(OverlayPresenterObserverBridgeTest, DidShowCalled) {
   ASSERT_FALSE(observer_.didShowCalled);
-  bridge_.DidShowOverlay(nullptr, nullptr);
+  bridge_.DidShowOverlay(/*presenter=*/nullptr, /*request=*/nullptr);
   EXPECT_TRUE(observer_.didShowCalled);
 }
 
@@ -94,7 +96,7 @@
 // forwarded.
 TEST_F(OverlayPresenterObserverBridgeTest, DidHideCalled) {
   ASSERT_FALSE(observer_.didHideCalled);
-  bridge_.DidHideOverlay(nullptr, nullptr);
+  bridge_.DidHideOverlay(/*presenter=*/nullptr, /*request=*/nullptr);
   EXPECT_TRUE(observer_.didHideCalled);
 }
 
@@ -102,6 +104,6 @@
 // forwarded.
 TEST_F(OverlayPresenterObserverBridgeTest, DestroyedCalled) {
   ASSERT_FALSE(observer_.destroyedCalled);
-  bridge_.OverlayPresenterDestroyed(nullptr);
+  bridge_.OverlayPresenterDestroyed(/*presenter=*/nullptr);
   EXPECT_TRUE(observer_.destroyedCalled);
 }
diff --git a/ios/chrome/browser/overlays/public/overlay_browser_agent_base.h b/ios/chrome/browser/overlays/public/overlay_browser_agent_base.h
index 1795048..2e2badce 100644
--- a/ios/chrome/browser/overlays/public/overlay_browser_agent_base.h
+++ b/ios/chrome/browser/overlays/public/overlay_browser_agent_base.h
@@ -63,7 +63,8 @@
     const OverlayRequestSupport* GetRequestSupport(
         OverlayPresenter* presenter) const override;
     void WillShowOverlay(OverlayPresenter* presenter,
-                         OverlayRequest* request) override;
+                         OverlayRequest* request,
+                         bool initial_presentation) override;
     void OverlayPresenterDestroyed(OverlayPresenter* presenter) override;
 
     Browser* browser_ = nullptr;
diff --git a/ios/chrome/browser/overlays/public/overlay_presenter_observer.h b/ios/chrome/browser/overlays/public/overlay_presenter_observer.h
index 36a37ac..ca6ba2b 100644
--- a/ios/chrome/browser/overlays/public/overlay_presenter_observer.h
+++ b/ios/chrome/browser/overlays/public/overlay_presenter_observer.h
@@ -25,8 +25,11 @@
       OverlayPresenter* presenter) const;
 
   // Called when |presenter| is about to show the overlay UI for |request|.
+  // |initial_presentation| is true if this is the first time the UI for
+  // |request| is being shown in the current OverlayPresentationContext.
   virtual void WillShowOverlay(OverlayPresenter* presenter,
-                               OverlayRequest* request) {}
+                               OverlayRequest* request,
+                               bool initial_presentation) {}
 
   // Called when |presenter| has finished showing the overlay UI for
   // |request|.
diff --git a/ios/chrome/browser/overlays/public/overlay_presenter_observer_bridge.h b/ios/chrome/browser/overlays/public/overlay_presenter_observer_bridge.h
index 1be2d51..a0ffffb 100644
--- a/ios/chrome/browser/overlays/public/overlay_presenter_observer_bridge.h
+++ b/ios/chrome/browser/overlays/public/overlay_presenter_observer_bridge.h
@@ -23,7 +23,8 @@
 
 // Invoked by OverlayPresenterObserver::WillShowOverlay().
 - (void)overlayPresenter:(OverlayPresenter*)presenter
-    willShowOverlayForRequest:(OverlayRequest*)request;
+    willShowOverlayForRequest:(OverlayRequest*)request
+          initialPresentation:(BOOL)initialPresentation;
 
 // Invoked by OverlayPresenterObserver::DidShowOverlay().
 - (void)overlayPresenter:(OverlayPresenter*)presenter
@@ -51,7 +52,8 @@
   const OverlayRequestSupport* GetRequestSupport(
       OverlayPresenter* presenter) const override;
   void WillShowOverlay(OverlayPresenter* presenter,
-                       OverlayRequest* request) override;
+                       OverlayRequest* request,
+                       bool initial_presentation) override;
   void DidShowOverlay(OverlayPresenter* presenter,
                       OverlayRequest* request) override;
   void DidHideOverlay(OverlayPresenter* presenter,
diff --git a/ios/chrome/browser/passwords/BUILD.gn b/ios/chrome/browser/passwords/BUILD.gn
index df1ba39..3bfc98c 100644
--- a/ios/chrome/browser/passwords/BUILD.gn
+++ b/ios/chrome/browser/passwords/BUILD.gn
@@ -11,6 +11,8 @@
     "credential_manager.mm",
     "ios_chrome_bulk_leak_check_service_factory.cc",
     "ios_chrome_bulk_leak_check_service_factory.h",
+    "ios_chrome_password_check_manager.h",
+    "ios_chrome_password_check_manager.mm",
     "ios_chrome_password_manager_client.h",
     "ios_chrome_password_manager_client.mm",
     "ios_chrome_password_manager_driver.h",
@@ -160,6 +162,7 @@
   testonly = true
   sources = [
     "credential_manager_unittest.mm",
+    "ios_chrome_password_check_manager_unittest.mm",
     "ios_chrome_password_manager_client_unittest.mm",
     "js_credential_manager_unittest.mm",
     "password_controller_js_unittest.mm",
diff --git a/ios/chrome/browser/passwords/ios_chrome_bulk_leak_check_service_factory.cc b/ios/chrome/browser/passwords/ios_chrome_bulk_leak_check_service_factory.cc
index 134398a..ca79560 100644
--- a/ios/chrome/browser/passwords/ios_chrome_bulk_leak_check_service_factory.cc
+++ b/ios/chrome/browser/passwords/ios_chrome_bulk_leak_check_service_factory.cc
@@ -10,6 +10,7 @@
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
 #include "components/password_manager/core/browser/bulk_leak_check_service.h"
+#include "components/password_manager/core/browser/bulk_leak_check_service_interface.h"
 #include "ios/chrome/browser/browser_state/browser_state_otr_helper.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/signin/identity_manager_factory.h"
@@ -24,10 +25,10 @@
 }
 
 // static
-password_manager::BulkLeakCheckService*
+password_manager::BulkLeakCheckServiceInterface*
 IOSChromeBulkLeakCheckServiceFactory::GetForBrowserState(
     ChromeBrowserState* browser_state) {
-  return static_cast<password_manager::BulkLeakCheckService*>(
+  return static_cast<password_manager::BulkLeakCheckServiceInterface*>(
       GetInstance()->GetServiceForBrowserState(browser_state, true));
 }
 
diff --git a/ios/chrome/browser/passwords/ios_chrome_bulk_leak_check_service_factory.h b/ios/chrome/browser/passwords/ios_chrome_bulk_leak_check_service_factory.h
index b9df56d..14de4fa 100644
--- a/ios/chrome/browser/passwords/ios_chrome_bulk_leak_check_service_factory.h
+++ b/ios/chrome/browser/passwords/ios_chrome_bulk_leak_check_service_factory.h
@@ -14,7 +14,7 @@
 enum class ServiceAccessType;
 
 namespace password_manager {
-class BulkLeakCheckService;
+class BulkLeakCheckServiceInterface;
 }
 
 // Singleton that owns all BulkLeakCheckServices and associates them with
@@ -23,7 +23,7 @@
     : public BrowserStateKeyedServiceFactory {
  public:
   static IOSChromeBulkLeakCheckServiceFactory* GetInstance();
-  static password_manager::BulkLeakCheckService* GetForBrowserState(
+  static password_manager::BulkLeakCheckServiceInterface* GetForBrowserState(
       ChromeBrowserState* browser_state);
 
  private:
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_check_manager.h b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.h
new file mode 100644
index 0000000..6f140ee
--- /dev/null
+++ b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.h
@@ -0,0 +1,123 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_PASSWORDS_IOS_CHROME_PASSWORD_CHECK_MANAGER_H_
+#define IOS_CHROME_BROWSER_PASSWORDS_IOS_CHROME_PASSWORD_CHECK_MANAGER_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
+#include "components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.h"
+#include "components/password_manager/core/browser/ui/compromised_credentials_manager.h"
+#include "components/password_manager/core/browser/ui/credential_utils.h"
+#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+
+// Enum which represents possible states of Password Check on UI.
+// It's created based on BulkLeakCheckService::State.
+enum class PasswordCheckState {
+  kIdle,
+  kRunning,
+  kSignedOut,
+  kOffline,
+  kNoPasswords,
+  kQuotaLimit,
+  kOther,
+};
+
+// This class handles the bulk password check feature.
+class IOSChromePasswordCheckManager
+    : public password_manager::SavedPasswordsPresenter::Observer,
+      public password_manager::CompromisedCredentialsManager::Observer,
+      public password_manager::BulkLeakCheckServiceInterface::Observer {
+ public:
+  class Observer : public base::CheckedObserver {
+   public:
+    virtual void PasswordCheckStatusChanged(PasswordCheckState state) {}
+    virtual void CompromisedCredentialsChanged(
+        password_manager::CompromisedCredentialsManager::CredentialsView
+            credentials) {}
+  };
+
+  explicit IOSChromePasswordCheckManager(ChromeBrowserState* browser_state);
+  ~IOSChromePasswordCheckManager() override;
+
+  // Requests to start a check for compromised passwords.
+  void StartPasswordCheck();
+
+  // Returns the current state of the password check.
+  PasswordCheckState GetPasswordCheckState() const;
+
+  // The elapsed time since the last full password check was performed.
+  base::Time GetLastPasswordCheckTime() const;
+
+  // Obtains all compromised credentials that are present in the password store.
+  std::vector<password_manager::CredentialWithPassword>
+  GetCompromisedCredentials() const;
+
+  void AddObserver(Observer* observer) { observers_.AddObserver(observer); }
+  void RemoveObserver(Observer* observer) {
+    observers_.RemoveObserver(observer);
+  }
+
+ private:
+  // password_manager::SavedPasswordsPresenter::Observer:
+  void OnSavedPasswordsChanged(
+      password_manager::SavedPasswordsPresenter::SavedPasswordsView passwords)
+      override;
+
+  // password_manager::CompromisedCredentialsProvider::Observer:
+  void OnCompromisedCredentialsChanged(
+      password_manager::CompromisedCredentialsManager::CredentialsView
+          credentials) override;
+
+  // password_manager::BulkLeakCheckServiceInterface::Observer:
+  void OnStateChanged(
+      password_manager::BulkLeakCheckServiceInterface::State state) override;
+  void OnCredentialDone(const password_manager::LeakCheckCredential& credential,
+                        password_manager::IsLeaked is_leaked) override;
+
+  void NotifyPasswordCheckStatusChanged();
+
+  // Remembers whether a password check is running right now.
+  bool is_check_running_ = false;
+
+  ChromeBrowserState* browser_state_ = nullptr;
+
+  // Handle to the password store, powering both |saved_passwords_presenter_|
+  // and |compromised_credentials_manager_|.
+  scoped_refptr<password_manager::PasswordStore> password_store_;
+
+  // Used by |compromised_credentials_manager_| to obtain the list of saved
+  // passwords.
+  password_manager::SavedPasswordsPresenter saved_passwords_presenter_;
+
+  // Used to obtain the list of compromised credentials.
+  password_manager::CompromisedCredentialsManager
+      compromised_credentials_manager_;
+
+  // Adapter used to start, monitor and stop a bulk leak check.
+  password_manager::BulkLeakCheckServiceAdapter
+      bulk_leak_check_service_adapter_;
+
+  // A scoped observer for |saved_passwords_presenter_|.
+  ScopedObserver<password_manager::SavedPasswordsPresenter,
+                 password_manager::SavedPasswordsPresenter::Observer>
+      observed_saved_passwords_presenter_{this};
+
+  // A scoped observer for |compromised_credentials_manager_|.
+  ScopedObserver<password_manager::CompromisedCredentialsManager,
+                 password_manager::CompromisedCredentialsManager::Observer>
+      observed_compromised_credentials_manager_{this};
+
+  // A scoped observer for the BulkLeakCheckService.
+  ScopedObserver<password_manager::BulkLeakCheckServiceInterface,
+                 password_manager::BulkLeakCheckServiceInterface::Observer>
+      observed_bulk_leak_check_service_{this};
+
+  // Observers to listen to password check changes.
+  base::ObserverList<Observer> observers_;
+};
+
+#endif  // IOS_CHROME_BROWSER_PASSWORDS_IOS_CHROME_PASSWORD_CHECK_MANAGER_H_
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm
new file mode 100644
index 0000000..b4e3dd2
--- /dev/null
+++ b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm
@@ -0,0 +1,137 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/passwords/ios_chrome_password_check_manager.h"
+#include "components/keyed_service/core/service_access_type.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "ios/chrome/browser/passwords/ios_chrome_bulk_leak_check_service_factory.h"
+#include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+using password_manager::CredentialWithPassword;
+using password_manager::LeakCheckCredential;
+using CompromisedCredentialsView =
+    password_manager::CompromisedCredentialsManager::CredentialsView;
+using SavedPasswordsView =
+    password_manager::SavedPasswordsPresenter::SavedPasswordsView;
+using State = password_manager::BulkLeakCheckServiceInterface::State;
+
+PasswordCheckState ConvertBulkCheckState(State state) {
+  switch (state) {
+    case State::kIdle:
+      return PasswordCheckState::kIdle;
+    case State::kRunning:
+      return PasswordCheckState::kRunning;
+    case State::kSignedOut:
+      return PasswordCheckState::kSignedOut;
+    case State::kNetworkError:
+      return PasswordCheckState::kOffline;
+    case State::kQuotaLimit:
+      return PasswordCheckState::kQuotaLimit;
+    case State::kCanceled:
+    case State::kTokenRequestFailure:
+    case State::kHashingFailure:
+    case State::kServiceError:
+      return PasswordCheckState::kOther;
+  }
+  NOTREACHED();
+  return PasswordCheckState::kIdle;
+}
+}  // namespace
+
+IOSChromePasswordCheckManager::IOSChromePasswordCheckManager(
+    ChromeBrowserState* browser_state)
+    : browser_state_(browser_state),
+      password_store_(IOSChromePasswordStoreFactory::GetForBrowserState(
+          browser_state,
+          ServiceAccessType::EXPLICIT_ACCESS)),
+      saved_passwords_presenter_(password_store_),
+      compromised_credentials_manager_(password_store_,
+                                       &saved_passwords_presenter_),
+      bulk_leak_check_service_adapter_(
+          &saved_passwords_presenter_,
+          IOSChromeBulkLeakCheckServiceFactory::GetForBrowserState(
+              browser_state),
+          browser_state->GetPrefs()) {
+  observed_saved_passwords_presenter_.Add(&saved_passwords_presenter_);
+  observed_compromised_credentials_manager_.Add(
+      &compromised_credentials_manager_);
+  observed_bulk_leak_check_service_.Add(
+      IOSChromeBulkLeakCheckServiceFactory::GetForBrowserState(browser_state));
+
+  // Instructs the presenter and manager to initialize and build their caches.
+  saved_passwords_presenter_.Init();
+  compromised_credentials_manager_.Init();
+}
+
+IOSChromePasswordCheckManager::~IOSChromePasswordCheckManager() = default;
+
+void IOSChromePasswordCheckManager::StartPasswordCheck() {
+  bulk_leak_check_service_adapter_.StartBulkLeakCheck();
+  is_check_running_ = true;
+}
+
+PasswordCheckState IOSChromePasswordCheckManager::GetPasswordCheckState()
+    const {
+  if (saved_passwords_presenter_.GetSavedPasswords().empty()) {
+    return PasswordCheckState::kNoPasswords;
+  }
+  return ConvertBulkCheckState(
+      bulk_leak_check_service_adapter_.GetBulkLeakCheckState());
+}
+
+base::Time IOSChromePasswordCheckManager::GetLastPasswordCheckTime() const {
+  return base::Time::FromDoubleT(browser_state_->GetPrefs()->GetDouble(
+      password_manager::prefs::kLastTimePasswordCheckCompleted));
+}
+
+std::vector<CredentialWithPassword>
+IOSChromePasswordCheckManager::GetCompromisedCredentials() const {
+  return compromised_credentials_manager_.GetCompromisedCredentials();
+}
+
+void IOSChromePasswordCheckManager::OnSavedPasswordsChanged(
+    SavedPasswordsView) {
+  // Observing saved passwords to update possible kNoPasswords state.
+  NotifyPasswordCheckStatusChanged();
+}
+
+void IOSChromePasswordCheckManager::OnCompromisedCredentialsChanged(
+    CompromisedCredentialsView credentials) {
+  for (auto& observer : observers_) {
+    observer.CompromisedCredentialsChanged(credentials);
+  }
+}
+
+void IOSChromePasswordCheckManager::OnStateChanged(State state) {
+  if (state == State::kIdle && is_check_running_) {
+    // Saving time of last successful password check
+    browser_state_->GetPrefs()->SetDouble(
+        password_manager::prefs::kLastTimePasswordCheckCompleted,
+        base::Time::Now().ToDoubleT());
+  }
+  if (state != State::kRunning) {
+    is_check_running_ = false;
+  }
+  NotifyPasswordCheckStatusChanged();
+}
+
+void IOSChromePasswordCheckManager::OnCredentialDone(
+    const LeakCheckCredential& credential,
+    password_manager::IsLeaked is_leaked) {
+  if (is_leaked) {
+    compromised_credentials_manager_.SaveCompromisedCredential(credential);
+  }
+}
+
+void IOSChromePasswordCheckManager::NotifyPasswordCheckStatusChanged() {
+  for (auto& observer : observers_) {
+    observer.PasswordCheckStatusChanged(GetPasswordCheckState());
+  }
+}
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm b/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm
new file mode 100644
index 0000000..61c2e9e8
--- /dev/null
+++ b/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm
@@ -0,0 +1,319 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/passwords/ios_chrome_password_check_manager.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/password_manager/core/browser/bulk_leak_check_service.h"
+#include "components/password_manager/core/browser/mock_bulk_leak_check_service.h"
+#include "components/password_manager/core/browser/mock_password_store.h"
+#include "components/password_manager/core/browser/password_manager_test_utils.h"
+#include "components/password_manager/core/browser/test_password_store.h"
+#include "components/password_manager/core/common/password_manager_features.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
+#include "ios/chrome/browser/passwords/ios_chrome_bulk_leak_check_service_factory.h"
+#include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
+#include "ios/web/public/test/web_task_environment.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+constexpr char kExampleCom[] = "https://example.com";
+
+constexpr char kUsername1[] = "alice";
+
+constexpr char kPassword1[] = "s3cre3t";
+
+using autofill::PasswordForm;
+using password_manager::BulkLeakCheckServiceInterface;
+using password_manager::CredentialWithPassword;
+using password_manager::MockBulkLeakCheckService;
+using password_manager::CompromisedCredentials;
+using password_manager::CompromiseType;
+using password_manager::CompromiseTypeFlags;
+using password_manager::IsLeaked;
+using password_manager::LeakCheckCredential;
+using password_manager::TestPasswordStore;
+using ::testing::AllOf;
+using ::testing::ElementsAre;
+using ::testing::Field;
+using ::testing::IsEmpty;
+using ::testing::StrictMock;
+
+using CompromisedCredentialsView =
+    password_manager::CompromisedCredentialsManager::CredentialsView;
+
+struct MockPasswordCheckManagerObserver
+    : IOSChromePasswordCheckManager::Observer {
+  MOCK_METHOD(void,
+              CompromisedCredentialsChanged,
+              (CompromisedCredentialsView),
+              (override));
+  MOCK_METHOD(void,
+              PasswordCheckStatusChanged,
+              (PasswordCheckState),
+              (override));
+};
+
+scoped_refptr<TestPasswordStore> CreateAndUseTestPasswordStore(
+    ChromeBrowserState* _browserState) {
+  return base::WrapRefCounted(static_cast<password_manager::TestPasswordStore*>(
+      IOSChromePasswordStoreFactory::GetInstance()
+          ->SetTestingFactoryAndUse(
+              _browserState,
+              base::BindRepeating(&password_manager::BuildPasswordStore<
+                                  web::BrowserState, TestPasswordStore>))
+          .get()));
+}
+
+MockBulkLeakCheckService* CreateAndUseBulkLeakCheckService(
+    ChromeBrowserState* _browserState) {
+  return static_cast<MockBulkLeakCheckService*>(
+      IOSChromeBulkLeakCheckServiceFactory::GetInstance()
+          ->SetTestingFactoryAndUse(
+              _browserState, base::BindLambdaForTesting([](web::BrowserState*) {
+                return std::unique_ptr<KeyedService>(
+                    std::make_unique<MockBulkLeakCheckService>());
+              })));
+}
+
+CompromisedCredentials MakeCompromised(
+    base::StringPiece signon_realm,
+    base::StringPiece username,
+    base::TimeDelta time_since_creation = base::TimeDelta(),
+    CompromiseType compromise_type = CompromiseType::kLeaked) {
+  return {
+      std::string(signon_realm),
+      base::ASCIIToUTF16(username),
+      base::Time::Now() - time_since_creation,
+      compromise_type,
+  };
+}
+
+PasswordForm MakeSavedPassword(
+    base::StringPiece signon_realm,
+    base::StringPiece username,
+    base::StringPiece password = kPassword1,
+    base::StringPiece username_element = base::StringPiece()) {
+  PasswordForm form;
+  form.signon_realm = std::string(signon_realm);
+  form.username_value = base::ASCIIToUTF16(username);
+  form.password_value = base::ASCIIToUTF16(password);
+  form.username_element = base::ASCIIToUTF16(username_element);
+  return form;
+}
+
+// Creates matcher for a given compromised credential
+auto ExpectCompromisedCredential(const std::string& signon_realm,
+                                 const base::StringPiece& username,
+                                 const base::StringPiece& password,
+                                 base::TimeDelta elapsed_time_since_compromise,
+                                 CompromiseTypeFlags compromise_type) {
+  return AllOf(
+      Field(&CredentialWithPassword::signon_realm, signon_realm),
+      Field(&CredentialWithPassword::username, base::ASCIIToUTF16(username)),
+      Field(&CredentialWithPassword::password, base::ASCIIToUTF16(password)),
+      Field(&CredentialWithPassword::create_time,
+            (base::Time::Now() - elapsed_time_since_compromise)),
+      Field(&CredentialWithPassword::compromise_type, compromise_type));
+}
+
+class IOSChromePasswordCheckManagerTest : public PlatformTest {
+ public:
+  IOSChromePasswordCheckManagerTest()
+      : browser_state_(TestChromeBrowserState::Builder().Build()),
+        bulk_leak_check_service_(
+            CreateAndUseBulkLeakCheckService(browser_state_.get())),
+        store_(CreateAndUseTestPasswordStore(browser_state_.get())),
+        manager_(browser_state_.get()) {
+    scoped_feature_list_.InitAndEnableFeature(
+        password_manager::features::kPasswordCheck);
+  }
+
+  void RunUntilIdle() { task_env_.RunUntilIdle(); }
+
+  ChromeBrowserState* browser_state() { return browser_state_.get(); }
+  TestPasswordStore& store() { return *store_; }
+  MockBulkLeakCheckService* service() { return bulk_leak_check_service_; }
+  IOSChromePasswordCheckManager& manager() { return manager_; }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  web::WebTaskEnvironment task_env_{
+      web::WebTaskEnvironment::Options::DEFAULT,
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+  std::unique_ptr<ChromeBrowserState> browser_state_;
+  MockBulkLeakCheckService* bulk_leak_check_service_;
+  scoped_refptr<TestPasswordStore> store_;
+  IOSChromePasswordCheckManager manager_;
+};
+}  // namespace
+
+// Sets up the password store with a password and compromised
+// credential. Verifies that the result is matching expectation.
+TEST_F(IOSChromePasswordCheckManagerTest, GetCompromisedCredentials) {
+  store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1));
+
+  store().AddCompromisedCredentials(
+      MakeCompromised(kExampleCom, kUsername1, base::TimeDelta::FromMinutes(1),
+                      CompromiseType::kLeaked));
+  RunUntilIdle();
+  EXPECT_THAT(
+      manager().GetCompromisedCredentials(),
+      ElementsAre(ExpectCompromisedCredential(
+          kExampleCom, kUsername1, kPassword1, base::TimeDelta::FromMinutes(1),
+          CompromiseTypeFlags::kCredentialLeaked)));
+}
+
+// Test that we don't create an entry in the password store if IsLeaked is
+// false.
+TEST_F(IOSChromePasswordCheckManagerTest, NoLeakedFound) {
+  store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1, kPassword1));
+  RunUntilIdle();
+
+  static_cast<BulkLeakCheckServiceInterface::Observer*>(&manager())
+      ->OnCredentialDone(LeakCheckCredential(base::ASCIIToUTF16(kUsername1),
+                                             base::ASCIIToUTF16(kPassword1)),
+                         IsLeaked(false));
+  RunUntilIdle();
+
+  EXPECT_THAT(manager().GetCompromisedCredentials(), IsEmpty());
+}
+
+// Test that a found leak creates a compromised credential in the password
+// store.
+TEST_F(IOSChromePasswordCheckManagerTest, OnLeakFoundCreatesCredential) {
+  store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1, kPassword1));
+  RunUntilIdle();
+
+  static_cast<BulkLeakCheckServiceInterface::Observer*>(&manager())
+      ->OnCredentialDone(LeakCheckCredential(base::ASCIIToUTF16(kUsername1),
+                                             base::ASCIIToUTF16(kPassword1)),
+                         IsLeaked(true));
+  RunUntilIdle();
+
+  EXPECT_THAT(
+      manager().GetCompromisedCredentials(),
+      ElementsAre(ExpectCompromisedCredential(
+          kExampleCom, kUsername1, kPassword1, base::TimeDelta::FromMinutes(0),
+          CompromiseTypeFlags::kCredentialLeaked)));
+}
+
+// Verifies that the case where the user has no saved passwords is reported
+// correctly.
+TEST_F(IOSChromePasswordCheckManagerTest, GetPasswordCheckStatusNoPasswords) {
+  EXPECT_EQ(PasswordCheckState::kNoPasswords,
+            manager().GetPasswordCheckState());
+}
+
+// Verifies that the case where the user has saved passwords is reported
+// correctly.
+TEST_F(IOSChromePasswordCheckManagerTest, GetPasswordCheckStatusIdle) {
+  store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1));
+  RunUntilIdle();
+
+  EXPECT_EQ(PasswordCheckState::kIdle, manager().GetPasswordCheckState());
+}
+
+// Checks that the default kLastTimePasswordCheckCompleted pref value is
+// treated as no completed run yet.
+TEST_F(IOSChromePasswordCheckManagerTest,
+       LastTimePasswordCheckCompletedNotSet) {
+  EXPECT_EQ(base::Time(), manager().GetLastPasswordCheckTime());
+}
+
+// Checks that a non-default kLastTimePasswordCheckCompleted pref value is
+// treated as a completed run.
+TEST_F(IOSChromePasswordCheckManagerTest, LastTimePasswordCheckCompletedIsSet) {
+  base::Time expected = base::Time::Now() - base::TimeDelta::FromMinutes(5);
+  browser_state()->GetPrefs()->SetDouble(
+      password_manager::prefs::kLastTimePasswordCheckCompleted,
+      expected.ToDoubleT());
+
+  EXPECT_THAT(expected, manager().GetLastPasswordCheckTime());
+}
+
+// Checks that a transition into the idle state after starting a check results
+// in resetting the kLastTimePasswordCheckCompleted pref to the current time.
+TEST_F(IOSChromePasswordCheckManagerTest, LastTimePasswordCheckCompletedReset) {
+  manager().StartPasswordCheck();
+  RunUntilIdle();
+
+  static_cast<BulkLeakCheckServiceInterface::Observer*>(&manager())
+      ->OnStateChanged(BulkLeakCheckServiceInterface::State::kIdle);
+
+  EXPECT_THAT(base::Time::Now(), manager().GetLastPasswordCheckTime());
+}
+
+// Tests whether adding and removing an observer works as expected.
+TEST_F(IOSChromePasswordCheckManagerTest,
+       NotifyObserversAboutCompromisedCredentialChanges) {
+  store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1));
+
+  RunUntilIdle();
+  StrictMock<MockPasswordCheckManagerObserver> observer;
+  manager().AddObserver(&observer);
+
+  // Adding a compromised credential should notify observers.
+  EXPECT_CALL(
+      observer,
+      CompromisedCredentialsChanged(ElementsAre(ExpectCompromisedCredential(
+          kExampleCom, kUsername1, kPassword1, base::TimeDelta::FromMinutes(1),
+          CompromiseTypeFlags::kCredentialLeaked))));
+  store().AddCompromisedCredentials(MakeCompromised(
+      kExampleCom, kUsername1, base::TimeDelta::FromMinutes(1)));
+  RunUntilIdle();
+
+  // After an observer is removed it should no longer receive notifications.
+  manager().RemoveObserver(&observer);
+  EXPECT_CALL(observer, CompromisedCredentialsChanged).Times(0);
+  store().AddCompromisedCredentials(
+      MakeCompromised(kExampleCom, kUsername1, base::TimeDelta::FromMinutes(1),
+                      CompromiseType::kPhished));
+  RunUntilIdle();
+}
+
+// Tests whether adding and removing an observer works as expected.
+TEST_F(IOSChromePasswordCheckManagerTest, NotifyObserversAboutStateChanges) {
+  store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1));
+  RunUntilIdle();
+  StrictMock<MockPasswordCheckManagerObserver> observer;
+  manager().AddObserver(&observer);
+
+  EXPECT_CALL(observer, PasswordCheckStatusChanged(PasswordCheckState::kIdle));
+  static_cast<BulkLeakCheckServiceInterface::Observer*>(&manager())
+      ->OnStateChanged(BulkLeakCheckServiceInterface::State::kIdle);
+
+  RunUntilIdle();
+
+  EXPECT_EQ(PasswordCheckState::kIdle, manager().GetPasswordCheckState());
+
+  // After an observer is removed it should no longer receive notifications.
+  manager().RemoveObserver(&observer);
+  EXPECT_CALL(observer, PasswordCheckStatusChanged).Times(0);
+  static_cast<BulkLeakCheckServiceInterface::Observer*>(&manager())
+      ->OnStateChanged(BulkLeakCheckServiceInterface::State::kRunning);
+  RunUntilIdle();
+}
diff --git a/ios/chrome/browser/translate/fake_translate_infobar_delegate.h b/ios/chrome/browser/translate/fake_translate_infobar_delegate.h
index e79952b..1ac6bc9 100644
--- a/ios/chrome/browser/translate/fake_translate_infobar_delegate.h
+++ b/ios/chrome/browser/translate/fake_translate_infobar_delegate.h
@@ -5,13 +5,22 @@
 #ifndef IOS_CHROME_BROWSER_TRANSLATE_FAKE_TRANSLATE_INFOBAR_DELEGATE_H_
 #define IOS_CHROME_BROWSER_TRANSLATE_FAKE_TRANSLATE_INFOBAR_DELEGATE_H_
 
-#include "components/sync_preferences/testing_pref_service_syncable.h"
-#include "components/translate/core/browser/mock_translate_client.h"
-#include "components/translate/core/browser/mock_translate_driver.h"
-#include "components/translate/core/browser/mock_translate_infobar_delegate.h"
-#include "components/translate/core/browser/mock_translate_ranker.h"
 #include "components/translate/core/browser/translate_infobar_delegate.h"
 
+#include "components/translate/core/browser/mock_translate_driver.h"
+
+namespace sync_preferences {
+class TestingPrefServiceSyncable;
+}
+namespace translate {
+class TranslateManager;
+namespace testing {
+class MockTranslateClient;
+class MockTranslateRanker;
+class MockLanguageModel;
+}  // namespace testing
+}  // namespace translate
+
 // Fake of TranslateInfoBarDelegate that allows for triggering Observer
 // callbacks.
 class FakeTranslateInfoBarDelegate
@@ -36,8 +45,14 @@
       translate::TranslateStep step,
       translate::TranslateErrors::Type error_type);
 
+  base::string16 original_language_name() const override;
+
+  base::string16 target_language_name() const override;
+
  private:
   base::ObserverList<Observer> observers_;
+  base::string16 original_language_;
+  base::string16 target_language_;
 };
 
 // Factory class to create instances of FakeTranslateInfoBarDelegate.
diff --git a/ios/chrome/browser/translate/fake_translate_infobar_delegate.mm b/ios/chrome/browser/translate/fake_translate_infobar_delegate.mm
index 3e74f97..0b8fbd5 100644
--- a/ios/chrome/browser/translate/fake_translate_infobar_delegate.mm
+++ b/ios/chrome/browser/translate/fake_translate_infobar_delegate.mm
@@ -4,6 +4,11 @@
 
 #import "ios/chrome/browser/translate/fake_translate_infobar_delegate.h"
 
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "components/translate/core/browser/mock_translate_client.h"
+#include "components/translate/core/browser/mock_translate_infobar_delegate.h"
+#include "components/translate/core/browser/mock_translate_ranker.h"
+
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
@@ -26,7 +31,9 @@
                                           original_language,
                                           target_language,
                                           error_type,
-                                          triggered_from_menu) {}
+                                          triggered_from_menu),
+      original_language_(original_language.begin(), original_language.end()),
+      target_language_(target_language.begin(), target_language.end()) {}
 
 FakeTranslateInfoBarDelegate::~FakeTranslateInfoBarDelegate() {
   for (auto& observer : observers_) {
@@ -50,6 +57,14 @@
   }
 }
 
+base::string16 FakeTranslateInfoBarDelegate::original_language_name() const {
+  return original_language_;
+}
+
+base::string16 FakeTranslateInfoBarDelegate::target_language_name() const {
+  return target_language_;
+}
+
 FakeTranslateInfoBarDelegateFactory::FakeTranslateInfoBarDelegateFactory() {
   pref_service_ =
       std::make_unique<sync_preferences::TestingPrefServiceSyncable>();
diff --git a/ios/chrome/browser/ui/browser_container/browser_container_mediator.mm b/ios/chrome/browser/ui/browser_container/browser_container_mediator.mm
index 5f3295f..e7006b9e 100644
--- a/ios/chrome/browser/ui/browser_container/browser_container_mediator.mm
+++ b/ios/chrome/browser/ui/browser_container/browser_container_mediator.mm
@@ -110,7 +110,8 @@
 #pragma mark - OverlayPresenterObserving
 
 - (void)overlayPresenter:(OverlayPresenter*)presenter
-    willShowOverlayForRequest:(OverlayRequest*)request {
+    willShowOverlayForRequest:(OverlayRequest*)request
+          initialPresentation:(BOOL)initialPresentation {
   self.showingAuthDialogForNonCommittedURL =
       IsActiveOverlayRequestForNonCommittedHttpAuthentication(
           self.webStateList);
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index ccafe8a1..ac809b9 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -26,7 +26,6 @@
 #import "components/signin/ios/browser/manage_accounts_delegate.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/translate/core/browser/translate_manager.h"
-#include "ios/chrome/app/tests_hook.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/download/download_manager_tab_helper.h"
@@ -61,7 +60,6 @@
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
 #import "ios/chrome/browser/ssl/captive_portal_detector_tab_helper.h"
 #import "ios/chrome/browser/ssl/captive_portal_detector_tab_helper_delegate.h"
-#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/translate/chrome_ios_translate_client.h"
 #import "ios/chrome/browser/ui/activity_services/requirements/activity_service_positioner.h"
 #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
@@ -82,6 +80,7 @@
 #import "ios/chrome/browser/ui/context_menu/context_menu_coordinator.h"
 #import "ios/chrome/browser/ui/download/download_manager_coordinator.h"
 #import "ios/chrome/browser/ui/elements/activity_overlay_coordinator.h"
+#import "ios/chrome/browser/ui/first_run/first_run_util.h"
 #import "ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_animator.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_features.h"
@@ -200,7 +199,8 @@
   ACTION_SEARCH_BY_IMAGE = 7,
   ACTION_OPEN_JAVASCRIPT = 8,
   ACTION_READ_LATER = 9,
-  NUM_ACTIONS = 10,
+  ACTION_OPEN_IN_NEW_WINDOW = 10,
+  NUM_ACTIONS = 11,
 };
 
 void Record(ContextMenuHistogram action, bool is_image, bool is_link) {
@@ -1666,9 +1666,7 @@
   // presented, to show a temporary view of the launch screen and then remove it
   // when the controller for the FRE has been presented. This fix should be
   // removed when the FRE startup code is rewritten.
-  BOOL firstRunLaunch = (FirstRun::IsChromeFirstRun() ||
-                         experimental_flags::AlwaysDisplayFirstRun()) &&
-                        !tests_hook::DisableFirstRun();
+  const bool firstRunLaunch = ShouldPresentFirstRunExperience();
   // These if statements check that |presentViewController| is being called for
   // the FRE case.
   if (firstRunLaunch &&
@@ -3003,8 +3001,9 @@
         title = l10n_util::GetNSStringWithFixup(
             IDS_IOS_CONTENT_CONTEXT_OPENINNEWWINDOW);
         action = ^{
-          // TODO(crbug.com/1073410): Record this in the
-          //   MobileWebContextMenuOpenInNewTab histogram.
+          base::RecordAction(
+              base::UserMetricsAction("MobileWebContextMenuOpenInNewWindow"));
+          Record(ACTION_OPEN_IN_NEW_WINDOW, isImage, isLink);
           // The "Open In New Window" item in the context menu opens a new tab
           // in a new window. This will be (according to |isOffTheRecord|)
           // incognito if the originating browser is incognito.
diff --git a/ios/chrome/browser/ui/first_run/BUILD.gn b/ios/chrome/browser/ui/first_run/BUILD.gn
index ed53961..5be12c90f 100644
--- a/ios/chrome/browser/ui/first_run/BUILD.gn
+++ b/ios/chrome/browser/ui/first_run/BUILD.gn
@@ -27,6 +27,7 @@
     "//components/metrics",
     "//components/prefs",
     "//components/signin/public/identity_manager",
+    "//ios/chrome/app:tests_hook",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state",
diff --git a/ios/chrome/browser/ui/first_run/first_run_util.h b/ios/chrome/browser/ui/first_run/first_run_util.h
index f6c8e4f4..a66fde0 100644
--- a/ios/chrome/browser/ui/first_run/first_run_util.h
+++ b/ios/chrome/browser/ui/first_run/first_run_util.h
@@ -41,4 +41,7 @@
 // Posts a notification that First Run did finish.
 void FirstRunDismissed();
 
+// Returns whether the First Run Experience should be presented.
+bool ShouldPresentFirstRunExperience();
+
 #endif  // IOS_CHROME_BROWSER_UI_FIRST_RUN_FIRST_RUN_UTIL_H_
diff --git a/ios/chrome/browser/ui/first_run/first_run_util.mm b/ios/chrome/browser/ui/first_run/first_run_util.mm
index 126c5bc..025c4af 100644
--- a/ios/chrome/browser/ui/first_run/first_run_util.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_util.mm
@@ -13,12 +13,14 @@
 #include "base/task/thread_pool.h"
 #include "base/time/time.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
+#import "ios/chrome/app/tests_hook.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/crash_report/breakpad_helper.h"
 #include "ios/chrome/browser/first_run/first_run.h"
 #import "ios/chrome/browser/first_run/first_run_configuration.h"
 #include "ios/chrome/browser/first_run/first_run_metrics.h"
 #include "ios/chrome/browser/signin/identity_manager_factory.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/settings/sync/utils/sync_util.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #include "ios/web/public/thread/web_thread.h"
@@ -74,11 +76,14 @@
                             first_run::SIGNIN_SIZE);
 }
 
+bool kFirstRunSentinelCreated = false;
+
 }  // namespace
 
 void WriteFirstRunSentinelAndRecordMetrics(ChromeBrowserState* browserState,
                                            BOOL sign_in_attempted,
                                            BOOL has_sso_account) {
+  kFirstRunSentinelCreated = true;
   base::ThreadPool::PostTask(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
       base::BindOnce(&CreateSentinel));
@@ -105,3 +110,16 @@
       postNotificationName:kChromeFirstRunUIDidFinishNotification
                     object:nil];
 }
+
+bool ShouldPresentFirstRunExperience() {
+  if (tests_hook::DisableFirstRun())
+    return false;
+
+  if (experimental_flags::AlwaysDisplayFirstRun())
+    return true;
+
+  if (kFirstRunSentinelCreated)
+    return false;
+
+  return FirstRun::IsChromeFirstRun();
+}
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm b/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm
index 7dec8be..c703746 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm
@@ -144,7 +144,8 @@
 #pragma mark - OverlayPresenterObserving
 
 - (void)overlayPresenter:(OverlayPresenter*)presenter
-    willShowOverlayForRequest:(OverlayRequest*)request {
+    willShowOverlayForRequest:(OverlayRequest*)request
+          initialPresentation:(BOOL)initialPresentation {
   self.webContentAreaShowingOverlay = YES;
   self.webContentAreaShowingHTTPAuthDialog =
       !!request->GetConfig<HTTPAuthOverlayRequestConfig>();
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm
index c8a27449..dcfda2d 100644
--- a/ios/chrome/browser/ui/main/scene_controller.mm
+++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -22,7 +22,6 @@
 #import "ios/chrome/app/chrome_overlay_window.h"
 #import "ios/chrome/app/deferred_initialization_runner.h"
 #import "ios/chrome/app/main_controller_guts.h"
-#import "ios/chrome/app/tests_hook.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_remove_mask.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_remover.h"
@@ -44,7 +43,6 @@
 #import "ios/chrome/browser/ntp_snippets/content_suggestions_scheduler_notifications.h"
 #include "ios/chrome/browser/signin/identity_manager_factory.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
-#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller.h"
 #import "ios/chrome/browser/ui/authentication/signin/signin_coordinator.h"
 #import "ios/chrome/browser/ui/authentication/signin/signin_utils.h"
@@ -312,6 +310,30 @@
                         startupInformation:self.mainController
                          interfaceProvider:self.interfaceProvider];
         }
+
+        // See if this scene launched as part of a multiwindow URL opening.
+        // If so, load that URL (this also creates a new tab to load the URL
+        // in). No other UI will show in this case.
+        NSUserActivity* activityWithCompletion;
+        for (NSUserActivity* activity in self.sceneState.connectionOptions
+                 .userActivities) {
+          if (ActivityIsURLLoad(activity)) {
+            UrlLoadParams params = LoadParamsFromActivity(activity);
+            UrlLoadingBrowserAgent::FromBrowser(self.mainInterface.browser)
+                ->Load(params);
+            return;
+          } else if (!activityWithCompletion) {
+            // Completion involves user interaction.
+            // Only one can be triggered.
+            activityWithCompletion = activity;
+          }
+        }
+        if (activityWithCompletion) {
+          [UserActivityHandler continueUserActivity:activityWithCompletion
+                                applicationIsActive:YES
+                                          tabOpener:self
+                                 startupInformation:self.mainController];
+        }
         self.sceneState.connectionOptions = nil;
 
         // Handle URL opening from
@@ -392,10 +414,25 @@
 - (void)sceneStateWillHideModalOverlay:(SceneState*)sceneState {
   [self.blockingOverlayViewController.view removeFromSuperview];
   self.blockingOverlayViewController = nil;
+
+  // When the scene has displayed the blocking overlay and isn't in foreground
+  // when it exits it, the cached app switcher snapshot will have the overlay on
+  // it, and therefore needs updating.
+  if (sceneState.activationLevel < SceneActivationLevelForegroundInactive) {
+    if (@available(iOS 13, *)) {
+      [[UIApplication sharedApplication]
+          requestSceneSessionRefresh:sceneState.scene.session];
+    }
+  }
 }
 
 // TODO(crbug.com/1072408): factor out into a new class.
 - (void)displayBlockingOverlay {
+  // Make the window visible. This is because in safe mode it's not visible yet.
+  if (self.sceneState.window.hidden) {
+    [self.sceneState.window makeKeyAndVisible];
+  }
+
   self.blockingOverlayViewController =
       [[BlockingOverlayViewController alloc] init];
   self.blockingOverlayViewController.blockingSceneCommandHandler =
@@ -441,6 +478,24 @@
                                   interfaceProvider:self.interfaceProvider];
 }
 
+- (void)sceneState:(SceneState*)sceneState
+    receivedUserActivity:(NSUserActivity*)userActivity {
+  if (self.mainController.appState.isInSafeMode || !userActivity) {
+    return;
+  }
+  BOOL sceneIsActive =
+      self.sceneState.activationLevel >= SceneActivationLevelForegroundActive;
+  [UserActivityHandler continueUserActivity:userActivity
+                        applicationIsActive:sceneIsActive
+                                  tabOpener:self
+                         startupInformation:self.mainController];
+  // It is necessary to reset the pendingUserActivity after handling it.
+  // Handle the reset asynchronously to avoid interfering with other observers.
+  dispatch_async(dispatch_get_main_queue(), ^{
+    self.sceneState.pendingUserActivity = nil;
+  });
+}
+
 #pragma mark - AppStateObserver
 
 - (void)appStateDidExitSafeMode:(AppState*)appState {
@@ -556,9 +611,7 @@
                             activeBrowser:self.currentInterface.browser];
 
   // Decide if the First Run UI needs to run.
-  BOOL firstRun = (FirstRun::IsChromeFirstRun() ||
-                   experimental_flags::AlwaysDisplayFirstRun()) &&
-                  !tests_hook::DisableFirstRun();
+  const bool firstRun = ShouldPresentFirstRunExperience();
 
   [self.browserViewWrangler switchGlobalStateToMode:launchMode];
 
@@ -573,23 +626,6 @@
 
   // Figure out what UI to show initially.
 
-  // See if this scene launched as part of a multiwindow URL opening.
-  // If so, load that URL (this also creates a new tab to load the URL in).
-  // No other UI will show in this case.
-  if (IsMultiwindowSupported()) {
-    if (@available(iOS 13, *)) {
-      for (NSUserActivity* activity in self.sceneState.connectionOptions
-               .userActivities) {
-        if (ActivityIsURLLoad(activity)) {
-          UrlLoadParams params = LoadParamsFromActivity(activity);
-          UrlLoadingBrowserAgent::FromBrowser(self.mainInterface.browser)
-              ->Load(params);
-          return;
-        }
-      }
-    }
-  }
-
   if (self.tabSwitcherIsActive) {
     DCHECK(!self.dismissingTabSwitcher);
     [self
diff --git a/ios/chrome/browser/ui/main/scene_delegate.mm b/ios/chrome/browser/ui/main/scene_delegate.mm
index 2706310..99a708b 100644
--- a/ios/chrome/browser/ui/main/scene_delegate.mm
+++ b/ios/chrome/browser/ui/main/scene_delegate.mm
@@ -125,4 +125,9 @@
                                completionHandler:completionHandler];
 }
 
+- (void)scene:(UIScene*)scene
+    continueUserActivity:(NSUserActivity*)userActivity API_AVAILABLE(ios(13)) {
+  self.sceneState.pendingUserActivity = userActivity;
+}
+
 @end
diff --git a/ios/chrome/browser/ui/main/scene_state.h b/ios/chrome/browser/ui/main/scene_state.h
index 94a8e76..caca3c0 100644
--- a/ios/chrome/browser/ui/main/scene_state.h
+++ b/ios/chrome/browser/ui/main/scene_state.h
@@ -47,6 +47,9 @@
 - (void)sceneState:(SceneState*)sceneState
     hasPendingURLs:(NSSet<UIOpenURLContext*>*)URLContexts
     API_AVAILABLE(ios(13));
+// Notifies that a new activity request has been received.
+- (void)sceneState:(SceneState*)sceneState
+    receivedUserActivity:(NSUserActivity*)userActivity;
 
 @end
 
@@ -100,6 +103,10 @@
 @property(nonatomic)
     NSSet<UIOpenURLContext*>* URLContextsToOpen API_AVAILABLE(ios(13));
 
+// A NSUserActivity that has been passed to
+// |UISceneDelegate scene:continueUserActivity:| and needs to be opened.
+@property(nonatomic) NSUserActivity* pendingUserActivity;
+
 // Adds an observer to this scene state. The observers will be notified about
 // scene state changes per SceneStateObserver protocol.
 - (void)addObserver:(id<SceneStateObserver>)observer;
diff --git a/ios/chrome/browser/ui/main/scene_state.mm b/ios/chrome/browser/ui/main/scene_state.mm
index 95bc4a9..b0dde39 100644
--- a/ios/chrome/browser/ui/main/scene_state.mm
+++ b/ios/chrome/browser/ui/main/scene_state.mm
@@ -124,6 +124,11 @@
   }
 }
 
+- (void)setPendingUserActivity:(NSUserActivity*)pendingUserActivity {
+  _pendingUserActivity = pendingUserActivity;
+  [self.observers sceneState:self receivedUserActivity:pendingUserActivity];
+}
+
 #pragma mark - debug
 
 - (NSString*)description {
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h
index 7f50e49..019f1d02 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h
@@ -57,10 +57,12 @@
                  size_t selected_line,
                  base::TimeTicks match_selection_timestamp) override;
   base::string16 GetText() const override;
-  void SetWindowTextAndCaretPos(const base::string16& text,
-                                size_t caret_pos,
-                                bool update_popup,
-                                bool notify_text_changed) override;
+  void SetWindowTextAndCaretPos(
+      const base::string16& text,
+      size_t caret_pos,
+      bool update_popup,
+      bool notify_text_changed,
+      const base::string16& additional_text = base::string16()) override;
   void SetCaretPos(size_t caret_pos) override;
   void RevertAll() override;
   void UpdatePopup() override;
@@ -68,8 +70,11 @@
                                    const AutocompleteMatch& match,
                                    bool save_original_selection,
                                    bool notify_text_changed) override;
-  bool OnInlineAutocompleteTextMaybeChanged(const base::string16& display_text,
-                                            size_t user_text_length) override;
+  void OnInlineAutocompleteTextMaybeChanged(
+      const base::string16& display_text,
+      size_t user_text_length,
+      size_t user_text_start = 0,
+      const base::string16& additional_text = base::string16()) override;
   void OnBeforePossibleChange() override;
   bool OnAfterPossibleChange(bool allow_keyword_ui_change) override;
   bool IsImeComposing() const override;
@@ -81,6 +86,7 @@
   bool IsSelectAll() const override;
   void GetSelectionBounds(base::string16::size_type* start,
                           base::string16::size_type* end) const override;
+  size_t GetAllSelectionsLength() const override;
   void SelectAll(bool reversed) override {}
   void SetFocus(bool is_user_initiated) override {}
   void ApplyCaretVisibility() override {}
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
index 6920f82..0b2c902 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
@@ -114,10 +114,12 @@
   return base::SysNSStringToUTF16([field_ displayedText]);
 }
 
-void OmniboxViewIOS::SetWindowTextAndCaretPos(const base::string16& text,
-                                              size_t caret_pos,
-                                              bool update_popup,
-                                              bool notify_text_changed) {
+void OmniboxViewIOS::SetWindowTextAndCaretPos(
+    const base::string16& text,
+    size_t caret_pos,
+    bool update_popup,
+    bool notify_text_changed,
+    const base::string16& additional_text) {
   // Do not call SetUserText() here, as the user has not triggered this change.
   // Instead, set the field's text directly.
   // Set the field_ value before calling ApplyTextAttributes(), because that
@@ -188,17 +190,16 @@
     model()->OnChanged();
 }
 
-bool OmniboxViewIOS::OnInlineAutocompleteTextMaybeChanged(
+void OmniboxViewIOS::OnInlineAutocompleteTextMaybeChanged(
     const base::string16& display_text,
-    size_t user_text_length) {
+    size_t user_text_length,
+    size_t user_text_start,
+    const base::string16& additional_text) {
   if (display_text == GetText())
-    return false;
+    return;
 
   NSAttributedString* as = ApplyTextAttributes(display_text);
   [field_ setText:as userTextLength:user_text_length];
-  if (model())
-    model()->OnChanged();
-  return true;
 }
 
 void OmniboxViewIOS::OnBeforePossibleChange() {
@@ -253,6 +254,10 @@
   }
 }
 
+size_t OmniboxViewIOS::GetAllSelectionsLength() const {
+  return 0;
+}
+
 gfx::NativeView OmniboxViewIOS::GetNativeView() const {
   return nullptr;
 }
diff --git a/ios/chrome/browser/ui/overlays/infobar_banner/BUILD.gn b/ios/chrome/browser/ui/overlays/infobar_banner/BUILD.gn
index e7b023e..c540922 100644
--- a/ios/chrome/browser/ui/overlays/infobar_banner/BUILD.gn
+++ b/ios/chrome/browser/ui/overlays/infobar_banner/BUILD.gn
@@ -8,7 +8,10 @@
 
   configs += [ "//build/config/compiler:enable_arc" ]
 
-  deps = [ ":coordinators" ]
+  deps = [
+    ":coordinators",
+    "//ios/chrome/browser/ui/overlays/infobar_banner/translate:coordinators",
+  ]
 }
 
 source_set("coordinators") {
@@ -31,6 +34,7 @@
     "//ios/chrome/browser/ui/overlays:util",
     "//ios/chrome/browser/ui/overlays/infobar_banner/confirm",
     "//ios/chrome/browser/ui/overlays/infobar_banner/passwords",
+    "//ios/chrome/browser/ui/overlays/infobar_banner/translate:mediators",
     "//ios/chrome/browser/ui/util",
   ]
 }
diff --git a/ios/chrome/browser/ui/overlays/infobar_banner/infobar_banner_overlay_coordinator.mm b/ios/chrome/browser/ui/overlays/infobar_banner/infobar_banner_overlay_coordinator.mm
index edacb5f..606c8b4 100644
--- a/ios/chrome/browser/ui/overlays/infobar_banner/infobar_banner_overlay_coordinator.mm
+++ b/ios/chrome/browser/ui/overlays/infobar_banner/infobar_banner_overlay_coordinator.mm
@@ -19,6 +19,7 @@
 #import "ios/chrome/browser/ui/overlays/infobar_banner/confirm/confirm_infobar_banner_overlay_mediator.h"
 #import "ios/chrome/browser/ui/overlays/infobar_banner/infobar_banner_overlay_mediator.h"
 #import "ios/chrome/browser/ui/overlays/infobar_banner/passwords/save_password_infobar_banner_overlay_mediator.h"
+#import "ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_banner_overlay_mediator.h"
 #import "ios/chrome/browser/ui/overlays/overlay_request_coordinator+subclassing.h"
 #import "ios/chrome/browser/ui/overlays/overlay_request_coordinator_delegate.h"
 #import "ios/chrome/browser/ui/overlays/overlay_request_mediator_util.h"
@@ -45,7 +46,8 @@
 + (NSArray<Class>*)supportedMediatorClasses {
   return @[
     [SavePasswordInfobarBannerOverlayMediator class],
-    [ConfirmInfobarBannerOverlayMediator class]
+    [ConfirmInfobarBannerOverlayMediator class],
+    [TranslateInfobarBannerOverlayMediator class],
   ];
 }
 
diff --git a/ios/chrome/browser/ui/overlays/infobar_banner/infobar_banner_supported_overlay_coordinator_classes.mm b/ios/chrome/browser/ui/overlays/infobar_banner/infobar_banner_supported_overlay_coordinator_classes.mm
index 9f1f81e..b0010031 100644
--- a/ios/chrome/browser/ui/overlays/infobar_banner/infobar_banner_supported_overlay_coordinator_classes.mm
+++ b/ios/chrome/browser/ui/overlays/infobar_banner/infobar_banner_supported_overlay_coordinator_classes.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/ui/overlays/infobar_banner/infobar_banner_supported_overlay_coordinator_classes.h"
 
 #import "ios/chrome/browser/ui/overlays/infobar_banner/infobar_banner_overlay_coordinator.h"
+#import "ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_placeholder_overlay_coordinator.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -13,7 +14,10 @@
 namespace infobar_banner {
 
 NSArray<Class>* GetSupportedOverlayCoordinatorClasses() {
-  return @ [[InfobarBannerOverlayCoordinator class]];
+  return @[
+    [InfobarBannerOverlayCoordinator class],
+    [TranslateInfobarPlaceholderOverlayCoordinator class]
+  ];
 }
 
 }  // infobar_banner
diff --git a/ios/chrome/browser/ui/overlays/infobar_banner/translate/BUILD.gn b/ios/chrome/browser/ui/overlays/infobar_banner/translate/BUILD.gn
new file mode 100644
index 0000000..d50f62b
--- /dev/null
+++ b/ios/chrome/browser/ui/overlays/infobar_banner/translate/BUILD.gn
@@ -0,0 +1,69 @@
+# 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.
+
+source_set("coordinators") {
+  sources = [
+    "translate_infobar_placeholder_overlay_coordinator.h",
+    "translate_infobar_placeholder_overlay_coordinator.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    "//ios/chrome/browser/overlays/public/common/infobars",
+    "//ios/chrome/browser/overlays/public/infobar_banner",
+    "//ios/chrome/browser/ui/overlays:coordinators",
+    "//ios/chrome/browser/ui/overlays/infobar_banner:coordinators",
+  ]
+}
+
+source_set("mediators") {
+  sources = [
+    "translate_infobar_banner_overlay_mediator.h",
+    "translate_infobar_banner_overlay_mediator.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    "//base",
+    "//ios/chrome/app/strings:ios_strings_grit",
+    "//ios/chrome/browser/overlays",
+    "//ios/chrome/browser/overlays/public/infobar_banner",
+    "//ios/chrome/browser/ui/infobars/banners",
+    "//ios/chrome/browser/ui/overlays:coordinators",
+    "//ios/chrome/browser/ui/overlays/infobar_banner:mediators",
+    "//ui/base",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [ "translate_infobar_banner_overlay_mediator_unittest.mm" ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    ":mediators",
+    "//base/test:test_support",
+    "//components/infobars/core",
+    "//components/strings:components_strings_grit",
+    "//components/translate/core/browser:test_support",
+    "//ios/chrome/app/strings:ios_strings_grit",
+    "//ios/chrome/browser/infobars",
+    "//ios/chrome/browser/overlays",
+    "//ios/chrome/browser/overlays/public/common/infobars",
+    "//ios/chrome/browser/overlays/public/infobar_banner",
+    "//ios/chrome/browser/overlays/test",
+    "//ios/chrome/browser/translate:test_support",
+    "//ios/chrome/browser/ui/infobars:feature_flags",
+    "//ios/chrome/browser/ui/infobars/banners/test",
+    "//ios/chrome/browser/ui/infobars/test",
+    "//ios/chrome/browser/ui/overlays:coordinators",
+    "//ios/chrome/browser/ui/overlays/test",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//ui/base",
+  ]
+}
diff --git a/ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_banner_overlay_mediator.h b/ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_banner_overlay_mediator.h
new file mode 100644
index 0000000..08a8b6a7
--- /dev/null
+++ b/ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_banner_overlay_mediator.h
@@ -0,0 +1,14 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_OVERLAYS_INFOBAR_BANNER_TRANSLATE_TRANSLATE_INFOBAR_BANNER_OVERLAY_MEDIATOR_H_
+#define IOS_CHROME_BROWSER_UI_OVERLAYS_INFOBAR_BANNER_TRANSLATE_TRANSLATE_INFOBAR_BANNER_OVERLAY_MEDIATOR_H_
+
+#import "ios/chrome/browser/ui/overlays/infobar_banner/infobar_banner_overlay_mediator.h"
+
+// Mediator that configures an infobar banner for a translate infobar.
+@interface TranslateInfobarBannerOverlayMediator : InfobarBannerOverlayMediator
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_OVERLAYS_INFOBAR_BANNER_TRANSLATE_TRANSLATE_INFOBAR_BANNER_OVERLAY_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_banner_overlay_mediator.mm b/ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_banner_overlay_mediator.mm
new file mode 100644
index 0000000..85bc6c9
--- /dev/null
+++ b/ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_banner_overlay_mediator.mm
@@ -0,0 +1,103 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_banner_overlay_mediator.h"
+
+#import "ios/chrome/browser/overlays/public/infobar_banner/infobar_banner_overlay_responses.h"
+#import "ios/chrome/browser/overlays/public/infobar_banner/translate_infobar_banner_overlay_request_config.h"
+#import "ios/chrome/browser/ui/infobars/banners/infobar_banner_consumer.h"
+#import "ios/chrome/browser/ui/overlays/infobar_banner/infobar_banner_overlay_mediator+consumer_support.h"
+#import "ios/chrome/browser/ui/overlays/overlay_request_mediator+subclassing.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+using translate_infobar_overlays::TranslateBannerRequestConfig;
+
+@interface TranslateInfobarBannerOverlayMediator ()
+// The translate banner config from the request.
+@property(nonatomic, readonly) TranslateBannerRequestConfig* config;
+@end
+
+@implementation TranslateInfobarBannerOverlayMediator
+
+#pragma mark - Accessors
+
+- (TranslateBannerRequestConfig*)config {
+  return self.request ? self.request->GetConfig<TranslateBannerRequestConfig>()
+                      : nullptr;
+}
+
+#pragma mark - OverlayRequestMediator
+
++ (const OverlayRequestSupport*)requestSupport {
+  return TranslateBannerRequestConfig::RequestSupport();
+}
+
+@end
+
+@implementation TranslateInfobarBannerOverlayMediator (ConsumerSupport)
+
+- (void)configureConsumer {
+  TranslateBannerRequestConfig* config = self.config;
+  if (!self.consumer || !config)
+    return;
+
+  [self.consumer setBannerAccessibilityLabel:[self bannerTitleText]];
+  [self.consumer setButtonText:[self infobarButtonText]];
+  [self.consumer setIconImage:[UIImage imageNamed:config->icon_image_name()]];
+  [self.consumer setPresentsModal:YES];
+  [self.consumer setTitleText:[self bannerTitleText]];
+  [self.consumer setSubtitleText:[self bannerSubtitleText]];
+}
+
+// Returns the title text of the banner depending on the
+// |self.config.translate_step()|.
+- (NSString*)bannerTitleText {
+  switch (self.config->translate_step()) {
+    case translate::TranslateStep::TRANSLATE_STEP_BEFORE_TRANSLATE:
+      return l10n_util::GetNSString(
+          IDS_IOS_TRANSLATE_INFOBAR_BEFORE_TRANSLATE_BANNER_TITLE);
+    case translate::TranslateStep::TRANSLATE_STEP_AFTER_TRANSLATE:
+      return l10n_util::GetNSString(
+          IDS_IOS_TRANSLATE_INFOBAR_AFTER_TRANSLATE_BANNER_TITLE);
+    case translate::TranslateStep::TRANSLATE_STEP_TRANSLATING:
+    case translate::TranslateStep::TRANSLATE_STEP_NEVER_TRANSLATE:
+    case translate::TranslateStep::TRANSLATE_STEP_TRANSLATE_ERROR:
+      NOTREACHED() << "Should not be presenting Banner in this TranslateStep";
+      return nil;
+  }
+}
+
+// Returns the subtitle text of the banner.
+- (NSString*)bannerSubtitleText {
+  // Formatted as "[source] to [target]".
+  return l10n_util::GetNSStringF(
+      IDS_IOS_TRANSLATE_INFOBAR_TRANSLATE_BANNER_SUBTITLE,
+      self.config->source_language(), self.config->target_language());
+}
+
+// Returns the text of the banner and modal action button depending on the
+// |self.config.translate_step()|.
+- (NSString*)infobarButtonText {
+  switch (self.config->translate_step()) {
+    case translate::TranslateStep::TRANSLATE_STEP_BEFORE_TRANSLATE:
+      return l10n_util::GetNSString(IDS_IOS_TRANSLATE_INFOBAR_TRANSLATE_ACTION);
+    case translate::TranslateStep::TRANSLATE_STEP_AFTER_TRANSLATE:
+      return l10n_util::GetNSString(
+          IDS_IOS_TRANSLATE_INFOBAR_TRANSLATE_UNDO_ACTION);
+    case translate::TranslateStep::TRANSLATE_STEP_TRANSLATING:
+    case translate::TranslateStep::TRANSLATE_STEP_NEVER_TRANSLATE:
+    case translate::TranslateStep::TRANSLATE_STEP_TRANSLATE_ERROR:
+      NOTREACHED() << "Translate infobar should not be presenting anything in "
+                      "this state.";
+      return nil;
+  }
+}
+
+@end
diff --git a/ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_banner_overlay_mediator_unittest.mm b/ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_banner_overlay_mediator_unittest.mm
new file mode 100644
index 0000000..b56b9bda
--- /dev/null
+++ b/ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_banner_overlay_mediator_unittest.mm
@@ -0,0 +1,72 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_banner_overlay_mediator.h"
+
+#include "base/feature_list.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/infobars/core/infobar.h"
+#include "components/infobars/core/infobar_feature.h"
+#include "ios/chrome/browser/infobars/infobar_ios.h"
+#import "ios/chrome/browser/overlays/public/infobar_banner/translate_infobar_banner_overlay_request_config.h"
+#import "ios/chrome/browser/translate/fake_translate_infobar_delegate.h"
+#import "ios/chrome/browser/ui/infobars/banners/test/fake_infobar_banner_consumer.h"
+#import "ios/chrome/browser/ui/infobars/infobar_feature.h"
+#include "ios/chrome/grit/ios_strings.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+using translate_infobar_overlays::TranslateBannerRequestConfig;
+
+// Test fixture for TranslateInfobarBannerOverlayMediator.
+class TranslateInfobarBannerOverlayMediatorTest : public PlatformTest {
+ public:
+  TranslateInfobarBannerOverlayMediatorTest() {
+    feature_list_.InitWithFeatures({kIOSInfobarUIReboot},
+                                   {kInfobarUIRebootOnlyiOS13});
+  }
+
+ protected:
+  base::test::ScopedFeatureList feature_list_;
+  FakeTranslateInfoBarDelegateFactory delegate_factory_;
+};
+
+// Tests that a TranslateInfobarBannerOverlayMediator correctly sets up its
+// consumer.
+TEST_F(TranslateInfobarBannerOverlayMediatorTest, SetUpConsumer) {
+  InfoBarIOS infobar(
+      InfobarType::kInfobarTypeTranslate,
+      delegate_factory_.CreateFakeTranslateInfoBarDelegate("fr", "en"));
+  // Package the infobar into an OverlayRequest, then create a mediator that
+  // uses this request in order to set up a fake consumer.
+  std::unique_ptr<OverlayRequest> request =
+      OverlayRequest::CreateWithConfig<TranslateBannerRequestConfig>(&infobar);
+  TranslateInfobarBannerOverlayMediator* mediator =
+      [[TranslateInfobarBannerOverlayMediator alloc]
+          initWithRequest:request.get()];
+  FakeInfobarBannerConsumer* consumer =
+      [[FakeInfobarBannerConsumer alloc] init];
+  mediator.consumer = consumer;
+  // Verify that the infobar was set up properly.
+  NSString* title = l10n_util::GetNSString(
+      IDS_IOS_TRANSLATE_INFOBAR_BEFORE_TRANSLATE_BANNER_TITLE);
+  NSString* subtitle = l10n_util::GetNSStringF(
+      IDS_IOS_TRANSLATE_INFOBAR_TRANSLATE_BANNER_SUBTITLE,
+      base::SysNSStringToUTF16(@"fr"), base::SysNSStringToUTF16(@"en"));
+
+  EXPECT_NSEQ(title, consumer.titleText);
+  EXPECT_NSEQ(
+      l10n_util::GetNSString(IDS_IOS_TRANSLATE_INFOBAR_TRANSLATE_ACTION),
+      consumer.buttonText);
+  EXPECT_NSEQ(subtitle, consumer.subtitleText);
+  EXPECT_NSEQ([UIImage imageNamed:@"infobar_translate_icon"],
+              consumer.iconImage);
+}
diff --git a/ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_placeholder_overlay_coordinator.h b/ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_placeholder_overlay_coordinator.h
new file mode 100644
index 0000000..688fff7
--- /dev/null
+++ b/ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_placeholder_overlay_coordinator.h
@@ -0,0 +1,17 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_OVERLAYS_INFOBAR_BANNER_TRANSLATE_TRANSLATE_INFOBAR_PLACEHOLDER_OVERLAY_COORDINATOR_H_
+#define IOS_CHROME_BROWSER_UI_OVERLAYS_INFOBAR_BANNER_TRANSLATE_TRANSLATE_INFOBAR_PLACEHOLDER_OVERLAY_COORDINATOR_H_
+
+#import "ios/chrome/browser/ui/overlays/infobar_banner/infobar_banner_overlay_coordinator.h"
+
+// A coordinator that displays nothing, serving as a placeholder between before
+// and after Translate banners so that no other overlays are presented while
+// Translate is finishing. It will not present or manage any UI.
+@interface TranslateInfobarPlaceholderOverlayCoordinator
+    : OverlayRequestCoordinator
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_OVERLAYS_INFOBAR_BANNER_TRANSLATE_TRANSLATE_INFOBAR_PLACEHOLDER_OVERLAY_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_placeholder_overlay_coordinator.mm b/ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_placeholder_overlay_coordinator.mm
new file mode 100644
index 0000000..f1766c42
--- /dev/null
+++ b/ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_placeholder_overlay_coordinator.mm
@@ -0,0 +1,49 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/overlays/infobar_banner/translate/translate_infobar_placeholder_overlay_coordinator.h"
+
+#import "ios/chrome/browser/overlays/public/common/infobars/infobar_overlay_request_config.h"
+#import "ios/chrome/browser/overlays/public/infobar_banner/infobar_banner_placeholder_request_config.h"
+#import "ios/chrome/browser/ui/overlays/overlay_request_coordinator+subclassing.h"
+#import "ios/chrome/browser/ui/overlays/overlay_request_coordinator_delegate.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface TranslateInfobarPlaceholderOverlayCoordinator ()
+// The list of supported mediator classes.
+@property(class, nonatomic, readonly) NSArray<Class>* supportedMediatorClasses;
+@end
+
+@implementation TranslateInfobarPlaceholderOverlayCoordinator
+
+#pragma mark - Accessors
+
++ (NSArray<Class>*)supportedMediatorClasses {
+  return @[];
+}
+
++ (const OverlayRequestSupport*)requestSupport {
+  return InfobarBannerPlaceholderRequestConfig::RequestSupport();
+}
+
+#pragma mark - OverlayRequestCoordinator
+
+- (void)startAnimated:(BOOL)animated {
+  self.started = YES;
+}
+
+- (void)stopAnimated:(BOOL)animated {
+  if (!self.started)
+    return;
+  // Notify the presentation context that the dismissal has finished.  This
+  // is necessary to synchronize OverlayPresenter scheduling logic with the UI
+  // layer.
+  self.delegate->OverlayUIDidFinishDismissal(self.request);
+  self.started = NO;
+}
+
+@end
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_fullscreen_disabler.h b/ios/chrome/browser/ui/overlays/overlay_presentation_context_fullscreen_disabler.h
index 4b01394..d78c512 100644
--- a/ios/chrome/browser/ui/overlays/overlay_presentation_context_fullscreen_disabler.h
+++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_fullscreen_disabler.h
@@ -38,7 +38,8 @@
    private:
     // OverlayPresenterObserver:
     void WillShowOverlay(OverlayPresenter* presenter,
-                         OverlayRequest* request) override;
+                         OverlayRequest* request,
+                         bool initial_presentation) override;
     void DidHideOverlay(OverlayPresenter* presenter,
                         OverlayRequest* request) override;
     void OverlayPresenterDestroyed(OverlayPresenter* presenter) override;
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_fullscreen_disabler.mm b/ios/chrome/browser/ui/overlays/overlay_presentation_context_fullscreen_disabler.mm
index bdd8844..2567f37 100644
--- a/ios/chrome/browser/ui/overlays/overlay_presentation_context_fullscreen_disabler.mm
+++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_fullscreen_disabler.mm
@@ -45,7 +45,8 @@
 
 void OverlayContainerFullscreenDisabler::FullscreenDisabler::WillShowOverlay(
     OverlayPresenter* presenter,
-    OverlayRequest* request) {
+    OverlayRequest* request,
+    bool initial_presentation) {
   disabler_ = std::make_unique<AnimatedScopedFullscreenDisabler>(
       fullscreen_controller_);
   disabler_->StartAnimation();
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
index b5af0e30..4791305 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
@@ -313,7 +313,8 @@
 #pragma mark - OverlayPresenterObserving
 
 - (void)overlayPresenter:(OverlayPresenter*)presenter
-    willShowOverlayForRequest:(OverlayRequest*)request {
+    willShowOverlayForRequest:(OverlayRequest*)request
+          initialPresentation:(BOOL)initialPresentation {
   self.webContentAreaShowingOverlay = YES;
 }
 
diff --git a/ios/chrome/browser/ui/settings/resources/BUILD.gn b/ios/chrome/browser/ui/settings/resources/BUILD.gn
index e1eea040..febf3ad 100644
--- a/ios/chrome/browser/ui/settings/resources/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/resources/BUILD.gn
@@ -182,3 +182,27 @@
     "sync_and_google_services_sync_on.imageset/sync_and_google_services_sync_on@3x.png",
   ]
 }
+
+imageset("settings_unsafe_state") {
+  sources = [
+    "settings_unsafe_state.imageset/Contents.json",
+    "settings_unsafe_state.imageset/settings_unsafe_state@2x.png",
+    "settings_unsafe_state.imageset/settings_unsafe_state@3x.png",
+  ]
+}
+
+imageset("settings_safe_state") {
+  sources = [
+    "settings_safe_state.imageset/Contents.json",
+    "settings_safe_state.imageset/settings_safe_state@2x.png",
+    "settings_safe_state.imageset/settings_safe_state@3x.png",
+  ]
+}
+
+imageset("settings_info") {
+  sources = [
+    "settings_info.imageset/Contents.json",
+    "settings_info.imageset/settings_info@2x.png",
+    "settings_info.imageset/settings_info@3x.png",
+  ]
+}
diff --git a/ios/chrome/browser/ui/settings/resources/settings_info.imageset/Contents.json b/ios/chrome/browser/ui/settings/resources/settings_info.imageset/Contents.json
new file mode 100644
index 0000000..b673aa2
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/resources/settings_info.imageset/Contents.json
@@ -0,0 +1,18 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "settings_info@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "settings_info@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
diff --git a/ios/chrome/browser/ui/settings/resources/settings_info.imageset/settings_info@2x.png b/ios/chrome/browser/ui/settings/resources/settings_info.imageset/settings_info@2x.png
new file mode 100644
index 0000000..56fa3ed
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/resources/settings_info.imageset/settings_info@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/settings/resources/settings_info.imageset/settings_info@3x.png b/ios/chrome/browser/ui/settings/resources/settings_info.imageset/settings_info@3x.png
new file mode 100644
index 0000000..1984e0c
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/resources/settings_info.imageset/settings_info@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/settings/resources/settings_safe_state.imageset/Contents.json b/ios/chrome/browser/ui/settings/resources/settings_safe_state.imageset/Contents.json
new file mode 100644
index 0000000..b00950d
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/resources/settings_safe_state.imageset/Contents.json
@@ -0,0 +1,18 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "settings_safe_state@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "settings_safe_state@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
diff --git a/ios/chrome/browser/ui/settings/resources/settings_safe_state.imageset/settings_safe_state@2x.png b/ios/chrome/browser/ui/settings/resources/settings_safe_state.imageset/settings_safe_state@2x.png
new file mode 100644
index 0000000..d2a78e1
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/resources/settings_safe_state.imageset/settings_safe_state@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/settings/resources/settings_safe_state.imageset/settings_safe_state@3x.png b/ios/chrome/browser/ui/settings/resources/settings_safe_state.imageset/settings_safe_state@3x.png
new file mode 100644
index 0000000..16b5358
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/resources/settings_safe_state.imageset/settings_safe_state@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/settings/resources/settings_unsafe_state.imageset/Contents.json b/ios/chrome/browser/ui/settings/resources/settings_unsafe_state.imageset/Contents.json
new file mode 100644
index 0000000..357c1638
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/resources/settings_unsafe_state.imageset/Contents.json
@@ -0,0 +1,18 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "settings_unsafe_state@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "settings_unsafe_state@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
diff --git a/ios/chrome/browser/ui/settings/resources/settings_unsafe_state.imageset/settings_unsafe_state@2x.png b/ios/chrome/browser/ui/settings/resources/settings_unsafe_state.imageset/settings_unsafe_state@2x.png
new file mode 100644
index 0000000..a00fa30
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/resources/settings_unsafe_state.imageset/settings_unsafe_state@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/settings/resources/settings_unsafe_state.imageset/settings_unsafe_state@3x.png b/ios/chrome/browser/ui/settings/resources/settings_unsafe_state.imageset/settings_unsafe_state@3x.png
new file mode 100644
index 0000000..ad13858
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/resources/settings_unsafe_state.imageset/settings_unsafe_state@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm b/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm
index 442db78..e3bf79e 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm
@@ -303,7 +303,6 @@
   CheckVisibilityInToolbar(BackButton(), ButtonVisibilityPrimary);
   CheckVisibilityInToolbar(ForwardButton(), ButtonVisibilityPrimary);
   CheckVisibilityInToolbar(NewTabButton(), ButtonVisibilityNone);
-  CheckVisibilityInToolbar(TabGridButton(), ButtonVisibilityNone);
   CheckVisibilityInToolbar(ToolsMenuButton(), ButtonVisibilityPrimary);
 
   // The secondary toolbar is not visible.
diff --git a/ios/chrome/browser/ui/toolbar/adaptive_toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/adaptive_toolbar_view_controller.mm
index db6bb28..09da6062 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive_toolbar_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive_toolbar_view_controller.mm
@@ -57,9 +57,7 @@
 #pragma mark - Public
 
 - (BOOL)areAnimationsEnabled {
-  return base::FeatureList::IsEnabled(kDisableAnimationOnLowBattery)
-             ? [UIView areAnimationsEnabled]
-             : YES;
+  return !base::FeatureList::IsEnabled(kDisableProgressBarAnimation);
 }
 
 - (void)updateForSideSwipeSnapshotOnNTP:(BOOL)onNTP {
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc
index 6c5f7bb..87df6f2 100644
--- a/ios/chrome/browser/ui/ui_feature_flags.cc
+++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -16,8 +16,8 @@
 const base::Feature kEmbedderBlockRestoreUrl{"EmbedderBlockRestoreUrl",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kDisableAnimationOnLowBattery{
-    "DisableAnimationOnLowBattery", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kDisableProgressBarAnimation{
+    "DisableProgressBarAnimation", base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kVoiceOverUnstackedTabstrip{
     "VoiceOverUnstackedTabstrip", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/ui_feature_flags.h b/ios/chrome/browser/ui/ui_feature_flags.h
index 3af7281..43988ee 100644
--- a/ios/chrome/browser/ui/ui_feature_flags.h
+++ b/ios/chrome/browser/ui/ui_feature_flags.h
@@ -17,8 +17,8 @@
 // Feature flag for embedders to block restore urls.
 extern const base::Feature kEmbedderBlockRestoreUrl;
 
-// Feature flag disabling animation on low battery.
-extern const base::Feature kDisableAnimationOnLowBattery;
+// Feature flag disabling progress bar animation.
+extern const base::Feature kDisableProgressBarAnimation;
 
 // Feature flag to use the unstacked tabstrip when voiceover is enabled.
 extern const base::Feature kVoiceOverUnstackedTabstrip;
diff --git a/ios/chrome/browser/web/restore_egtest.mm b/ios/chrome/browser/web/restore_egtest.mm
index fb03049..84e8fd73 100644
--- a/ios/chrome/browser/web/restore_egtest.mm
+++ b/ios/chrome/browser/web/restore_egtest.mm
@@ -147,8 +147,12 @@
 
 // Navigates to a set of cross-domains, chrome URLs and error pages, and then
 // tests that they are properly restored.
-// TODO(crbug.com/1073932): Re-enable this.
-- (void)DISABLED_testRestoreHistory {
+#if defined(CHROME_EARL_GREY_1)
+#define MAYBE_testRestoreHistory DISABLED_testRestoreHistory
+#else
+#define MAYBE_testRestoreHistory testRestoreHistory
+#endif
+- (void)MAYBE_testRestoreHistory {
   [self setUpRestoreServers];
   [self loadTestPages];
   [self verifyRestoredTestPages:YES];
@@ -156,8 +160,12 @@
 
 // Navigates to a set of cross-domains, chrome URLs and error pages, and then
 // tests that they are properly restored in airplane mode.
-// TODO(crbug.com/1073932): Re-enable this.
-- (void)DISABLED_testRestoreNoNetwork {
+#if defined(CHROME_EARL_GREY_1)
+#define MAYBE_testRestoreNoNetwork DISABLED_testRestoreNoNetwork
+#else
+#define MAYBE_testRestoreNoNetwork testRestoreNoNetwork
+#endif
+- (void)MAYBE_testRestoreNoNetwork {
   [self setUpRestoreServers];
   [self loadTestPages];
   self.serverRespondsWithContent = false;
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index a1facc8e..6b7ea4a 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -204,6 +204,7 @@
     "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common:unit_tests",
     "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/confirm:unit_tests",
     "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords:unit_tests",
+    "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate:unit_tests",
     "//ios/chrome/browser/itunes_urls:unit_tests",
     "//ios/chrome/browser/json_parser:unit_tests",
     "//ios/chrome/browser/language:unit_tests",
@@ -289,6 +290,7 @@
     "//ios/chrome/browser/ui/overlays/infobar_banner:unit_tests",
     "//ios/chrome/browser/ui/overlays/infobar_banner/confirm:unit_tests",
     "//ios/chrome/browser/ui/overlays/infobar_banner/passwords:unit_tests",
+    "//ios/chrome/browser/ui/overlays/infobar_banner/translate:unit_tests",
     "//ios/chrome/browser/ui/overlays/infobar_modal:unit_tests",
     "//ios/chrome/browser/ui/overlays/infobar_modal/passwords:unit_tests",
     "//ios/chrome/browser/ui/overlays/test_modality:unit_tests",
diff --git a/ios/web/common/features.h b/ios/web/common/features.h
index e1c41c0..947032f9 100644
--- a/ios/web/common/features.h
+++ b/ios/web/common/features.h
@@ -53,10 +53,6 @@
 // When enabled, display an interstitial on lookalike URL navigations.
 extern const base::Feature kIOSLookalikeUrlNavigationSuggestionsUI;
 
-// Level at which battery power is considered low, and some cosmetic features
-// can be turned off.
-const float kLowBatteryLevelThreshold = 0.2;
-
 // When true, for each navigation, the default user agent is chosen by the
 // WebClient GetDefaultUserAgent() method. If it is false, the mobile version
 // is requested by default.
diff --git a/ios/web/web_state/ui/crw_web_request_controller.mm b/ios/web/web_state/ui/crw_web_request_controller.mm
index d7dea86a..433aa41 100644
--- a/ios/web/web_state/ui/crw_web_request_controller.mm
+++ b/ios/web/web_state/ui/crw_web_request_controller.mm
@@ -425,18 +425,6 @@
       UMA_HISTOGRAM_TIMES("PLT.iOS.BrowserInitiatedPageLoadTime",
                           context->GetElapsedTimeSinceCreation());
     }
-    if ([UIDevice currentDevice].batteryLevel <
-        web::features::kLowBatteryLevelThreshold) {
-      if (context->IsRendererInitiated()) {
-        UMA_HISTOGRAM_TIMES(
-            "PLT.iOS.RendererInitiatedPageLoadTimeWithLowBattery",
-            context->GetElapsedTimeSinceCreation());
-      } else {
-        UMA_HISTOGRAM_TIMES(
-            "PLT.iOS.BrowserInitiatedPageLoadTimeWithLowBattery",
-            context->GetElapsedTimeSinceCreation());
-      }
-    }
   }
 }
 
diff --git a/media/base/android/android_cdm_factory.cc b/media/base/android/android_cdm_factory.cc
index a2c20394f..faa670f 100644
--- a/media/base/android/android_cdm_factory.cc
+++ b/media/base/android/android_cdm_factory.cc
@@ -43,7 +43,6 @@
 
 void AndroidCdmFactory::Create(
     const std::string& key_system,
-    const url::Origin& security_origin,
     const CdmConfig& cdm_config,
     const SessionMessageCB& session_message_cb,
     const SessionClosedCB& session_closed_cb,
@@ -56,11 +55,6 @@
   CdmCreatedCB bound_cdm_created_cb =
       BindToCurrentLoop(std::move(cdm_created_cb));
 
-  if (security_origin.opaque()) {
-    std::move(bound_cdm_created_cb).Run(nullptr, "Invalid origin.");
-    return;
-  }
-
   // Create AesDecryptor here to support External Clear Key key system.
   // This is used for testing.
   if (base::FeatureList::IsEnabled(media::kExternalClearKeyForTesting) &&
@@ -92,9 +86,9 @@
       creation_id_,
       PendingCreation(std::move(factory), std::move(bound_cdm_created_cb)));
 
-  raw_factory->Create(key_system, security_origin, cdm_config,
-                      session_message_cb, session_closed_cb,
-                      session_keys_change_cb, session_expiration_update_cb,
+  raw_factory->Create(key_system, cdm_config, session_message_cb,
+                      session_closed_cb, session_keys_change_cb,
+                      session_expiration_update_cb,
                       base::BindOnce(&AndroidCdmFactory::OnCdmCreated,
                                      weak_factory_.GetWeakPtr(), creation_id_));
 }
diff --git a/media/base/android/android_cdm_factory.h b/media/base/android/android_cdm_factory.h
index b32b793..ce24106 100644
--- a/media/base/android/android_cdm_factory.h
+++ b/media/base/android/android_cdm_factory.h
@@ -29,7 +29,6 @@
 
   // CdmFactory implementation.
   void Create(const std::string& key_system,
-              const url::Origin& security_origin,
               const CdmConfig& cdm_config,
               const SessionMessageCB& session_message_cb,
               const SessionClosedCB& session_closed_cb,
diff --git a/media/base/android/media_drm_bridge_factory.cc b/media/base/android/media_drm_bridge_factory.cc
index 52b3e01..ee3e4dcd 100644
--- a/media/base/android/media_drm_bridge_factory.cc
+++ b/media/base/android/media_drm_bridge_factory.cc
@@ -9,7 +9,6 @@
 #include "media/base/cdm_config.h"
 #include "media/base/content_decryption_module.h"
 #include "third_party/widevine/cdm/widevine_cdm_common.h"
-#include "url/origin.h"
 
 namespace media {
 
@@ -28,7 +27,6 @@
 
 void MediaDrmBridgeFactory::Create(
     const std::string& key_system,
-    const url::Origin& security_origin,
     const CdmConfig& cdm_config,
     const SessionMessageCB& session_message_cb,
     const SessionClosedCB& session_closed_cb,
@@ -37,7 +35,6 @@
     CdmCreatedCB cdm_created_cb) {
   DCHECK(MediaDrmBridge::IsKeySystemSupported(key_system));
   DCHECK(MediaDrmBridge::IsAvailable());
-  DCHECK(!security_origin.opaque());
   DCHECK(scheme_uuid_.empty()) << "This factory can only be used once.";
 
   scheme_uuid_ = MediaDrmBridge::GetUUID(key_system);
diff --git a/media/base/android/media_drm_bridge_factory.h b/media/base/android/media_drm_bridge_factory.h
index 4dfa133d..6df430ad 100644
--- a/media/base/android/media_drm_bridge_factory.h
+++ b/media/base/android/media_drm_bridge_factory.h
@@ -32,7 +32,6 @@
 
   // CdmFactory implementation.
   void Create(const std::string& key_system,
-              const url::Origin& security_origin,
               const CdmConfig& cdm_config,
               const SessionMessageCB& session_message_cb,
               const SessionClosedCB& session_closed_cb,
diff --git a/media/base/cdm_factory.h b/media/base/cdm_factory.h
index 29d764d8..96fcf3a8 100644
--- a/media/base/cdm_factory.h
+++ b/media/base/cdm_factory.h
@@ -34,7 +34,6 @@
   // asynchronously.
   virtual void Create(
       const std::string& key_system,
-      const url::Origin& security_origin,
       const CdmConfig& cdm_config,
       const SessionMessageCB& session_message_cb,
       const SessionClosedCB& session_closed_cb,
diff --git a/media/base/mock_filters.cc b/media/base/mock_filters.cc
index e16cd6a..109903cb 100644
--- a/media/base/mock_filters.cc
+++ b/media/base/mock_filters.cc
@@ -172,13 +172,11 @@
 }
 
 MockCdm::MockCdm(const std::string& key_system,
-                 const url::Origin& security_origin,
                  const SessionMessageCB& session_message_cb,
                  const SessionClosedCB& session_closed_cb,
                  const SessionKeysChangeCB& session_keys_change_cb,
                  const SessionExpirationUpdateCB& session_expiration_update_cb)
     : key_system_(key_system),
-      security_origin_(security_origin),
       session_message_cb_(session_message_cb),
       session_closed_cb_(session_closed_cb),
       session_keys_change_cb_(session_keys_change_cb),
@@ -214,7 +212,6 @@
 
 void MockCdmFactory::Create(
     const std::string& key_system,
-    const url::Origin& security_origin,
     const CdmConfig& /* cdm_config */,
     const SessionMessageCB& session_message_cb,
     const SessionClosedCB& session_closed_cb,
@@ -236,8 +233,8 @@
   // get the MockCdm via MockCdmFactory::GetCreatedCdm() and explicitly specify
   // expectations using EXPECT_CALL.
   scoped_refptr<MockCdm> cdm = new NiceMock<MockCdm>(
-      key_system, security_origin, session_message_cb, session_closed_cb,
-      session_keys_change_cb, session_expiration_update_cb);
+      key_system, session_message_cb, session_closed_cb, session_keys_change_cb,
+      session_expiration_update_cb);
   created_cdm_ = cdm.get();
   std::move(cdm_created_cb).Run(std::move(cdm), "");
 }
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h
index 1d90091..0ab0d102 100644
--- a/media/base/mock_filters.h
+++ b/media/base/mock_filters.h
@@ -575,7 +575,6 @@
 class MockCdm : public ContentDecryptionModule {
  public:
   MockCdm(const std::string& key_system,
-          const url::Origin& security_origin,
           const SessionMessageCB& session_message_cb,
           const SessionClosedCB& session_closed_cb,
           const SessionKeysChangeCB& session_keys_change_cb,
@@ -646,7 +645,6 @@
   // created CDM is passed to |cdm_created_cb|, a copy is kept (and available
   // using Cdm()). If |key_system| is empty, no CDM will be created.
   void Create(const std::string& key_system,
-              const url::Origin& security_origin,
               const CdmConfig& cdm_config,
               const SessionMessageCB& session_message_cb,
               const SessionClosedCB& session_closed_cb,
diff --git a/media/blink/cdm_session_adapter.cc b/media/blink/cdm_session_adapter.cc
index f29c841..a2fa29db 100644
--- a/media/blink/cdm_session_adapter.cc
+++ b/media/blink/cdm_session_adapter.cc
@@ -20,7 +20,6 @@
 #include "media/base/key_systems.h"
 #include "media/blink/webcontentdecryptionmodulesession_impl.h"
 #include "media/cdm/cdm_context_ref_impl.h"
-#include "url/origin.h"
 
 namespace media {
 
@@ -37,7 +36,6 @@
 
 void CdmSessionAdapter::CreateCdm(CdmFactory* cdm_factory,
                                   const std::string& key_system,
-                                  const url::Origin& security_origin,
                                   const CdmConfig& cdm_config,
                                   WebCdmCreatedCB web_cdm_created_cb) {
   TRACE_EVENT_ASYNC_BEGIN0("media", "CdmSessionAdapter::CreateCdm",
@@ -54,7 +52,7 @@
   web_cdm_created_cb_ = std::move(web_cdm_created_cb);
 
   cdm_factory->Create(
-      key_system, security_origin, cdm_config,
+      key_system, cdm_config,
       base::Bind(&CdmSessionAdapter::OnSessionMessage, weak_this),
       base::Bind(&CdmSessionAdapter::OnSessionClosed, weak_this),
       base::Bind(&CdmSessionAdapter::OnSessionKeysChange, weak_this),
diff --git a/media/blink/cdm_session_adapter.h b/media/blink/cdm_session_adapter.h
index 99576662..3325504 100644
--- a/media/blink/cdm_session_adapter.h
+++ b/media/blink/cdm_session_adapter.h
@@ -21,10 +21,6 @@
 #include "media/blink/webcontentdecryptionmodule_impl.h"
 #include "third_party/blink/public/platform/web_content_decryption_module_session.h"
 
-namespace url {
-class Origin;
-}
-
 namespace media {
 
 struct CdmConfig;
@@ -44,7 +40,6 @@
   // via |result|.
   void CreateCdm(CdmFactory* cdm_factory,
                  const std::string& key_system,
-                 const url::Origin& security_origin,
                  const CdmConfig& cdm_config,
                  WebCdmCreatedCB web_cdm_created_cb);
 
diff --git a/media/blink/webcontentdecryptionmodule_impl.cc b/media/blink/webcontentdecryptionmodule_impl.cc
index d0dded5..b267d9d7 100644
--- a/media/blink/webcontentdecryptionmodule_impl.cc
+++ b/media/blink/webcontentdecryptionmodule_impl.cc
@@ -107,7 +107,7 @@
   // |web_cdm_created_cb|), it will keep a reference to |adapter|. Otherwise,
   // |adapter| will be destructed.
   scoped_refptr<CdmSessionAdapter> adapter(new CdmSessionAdapter());
-  adapter->CreateCdm(cdm_factory, key_system_ascii, security_origin, cdm_config,
+  adapter->CreateCdm(cdm_factory, key_system_ascii, cdm_config,
                      std::move(web_cdm_created_cb));
 }
 
diff --git a/media/cdm/cdm_adapter_factory.cc b/media/cdm/cdm_adapter_factory.cc
index 61e7480..7af6fbd 100644
--- a/media/cdm/cdm_adapter_factory.cc
+++ b/media/cdm/cdm_adapter_factory.cc
@@ -22,7 +22,6 @@
 
 void CdmAdapterFactory::Create(
     const std::string& key_system,
-    const url::Origin& security_origin,
     const CdmConfig& cdm_config,
     const SessionMessageCB& session_message_cb,
     const SessionClosedCB& session_closed_cb,
@@ -31,14 +30,6 @@
     CdmCreatedCB cdm_created_cb) {
   DVLOG(1) << __func__ << ": key_system=" << key_system;
 
-  if (security_origin.opaque()) {
-    LOG(ERROR) << "Invalid Origin: " << security_origin;
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(std::move(cdm_created_cb), nullptr, "Invalid origin."));
-    return;
-  }
-
   CdmAdapter::CreateCdmFunc create_cdm_func =
       CdmModule::GetInstance()->GetCreateCdmFunc();
   if (!create_cdm_func) {
diff --git a/media/cdm/cdm_adapter_factory.h b/media/cdm/cdm_adapter_factory.h
index 2bffc6ec..a7ed60d 100644
--- a/media/cdm/cdm_adapter_factory.h
+++ b/media/cdm/cdm_adapter_factory.h
@@ -26,7 +26,6 @@
 
   // CdmFactory implementation.
   void Create(const std::string& key_system,
-              const url::Origin& security_origin,
               const CdmConfig& cdm_config,
               const SessionMessageCB& session_message_cb,
               const SessionClosedCB& session_closed_cb,
diff --git a/media/cdm/default_cdm_factory.cc b/media/cdm/default_cdm_factory.cc
index 2d1ea7e..49b7ae0 100644
--- a/media/cdm/default_cdm_factory.cc
+++ b/media/cdm/default_cdm_factory.cc
@@ -34,20 +34,12 @@
 
 void DefaultCdmFactory::Create(
     const std::string& key_system,
-    const url::Origin& security_origin,
     const CdmConfig& cdm_config,
     const SessionMessageCB& session_message_cb,
     const SessionClosedCB& session_closed_cb,
     const SessionKeysChangeCB& session_keys_change_cb,
     const SessionExpirationUpdateCB& session_expiration_update_cb,
     CdmCreatedCB cdm_created_cb) {
-  if (security_origin.opaque()) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(std::move(cdm_created_cb), nullptr, "Invalid origin."));
-    return;
-  }
-
   if (!ShouldCreateAesDecryptor(key_system)) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(cdm_created_cb), nullptr,
diff --git a/media/cdm/default_cdm_factory.h b/media/cdm/default_cdm_factory.h
index 5c1941ec..62c50f22 100644
--- a/media/cdm/default_cdm_factory.h
+++ b/media/cdm/default_cdm_factory.h
@@ -20,7 +20,6 @@
 
   // CdmFactory implementation.
   void Create(const std::string& key_system,
-              const url::Origin& security_origin,
               const CdmConfig& cdm_config,
               const SessionMessageCB& session_message_cb,
               const SessionClosedCB& session_closed_cb,
diff --git a/media/fuchsia/cdm/fuchsia_cdm_factory.cc b/media/fuchsia/cdm/fuchsia_cdm_factory.cc
index a95c5e3e..0f2e582 100644
--- a/media/fuchsia/cdm/fuchsia_cdm_factory.cc
+++ b/media/fuchsia/cdm/fuchsia_cdm_factory.cc
@@ -25,7 +25,6 @@
 
 void FuchsiaCdmFactory::Create(
     const std::string& key_system,
-    const url::Origin& security_origin,
     const CdmConfig& cdm_config,
     const SessionMessageCB& session_message_cb,
     const SessionClosedCB& session_closed_cb,
@@ -35,11 +34,6 @@
   CdmCreatedCB bound_cdm_created_cb =
       BindToCurrentLoop(std::move(cdm_created_cb));
 
-  if (security_origin.opaque()) {
-    std::move(bound_cdm_created_cb).Run(nullptr, "Invalid origin.");
-    return;
-  }
-
   if (CanUseAesDecryptor(key_system)) {
     auto cdm = base::MakeRefCounted<AesDecryptor>(
         session_message_cb, session_closed_cb, session_keys_change_cb,
diff --git a/media/fuchsia/cdm/fuchsia_cdm_factory.h b/media/fuchsia/cdm/fuchsia_cdm_factory.h
index ad8cd92..76f4c05 100644
--- a/media/fuchsia/cdm/fuchsia_cdm_factory.h
+++ b/media/fuchsia/cdm/fuchsia_cdm_factory.h
@@ -22,7 +22,6 @@
 
   // CdmFactory implementation.
   void Create(const std::string& key_system,
-              const url::Origin& security_origin,
               const CdmConfig& cdm_config,
               const SessionMessageCB& session_message_cb,
               const SessionClosedCB& session_closed_cb,
diff --git a/media/mojo/clients/mojo_cdm.cc b/media/mojo/clients/mojo_cdm.cc
index acc9d1c..df477ee 100644
--- a/media/mojo/clients/mojo_cdm.cc
+++ b/media/mojo/clients/mojo_cdm.cc
@@ -23,7 +23,6 @@
 #include "media/mojo/mojom/decryptor.mojom.h"
 #include "services/service_manager/public/cpp/connect.h"
 #include "services/service_manager/public/mojom/interface_provider.mojom.h"
-#include "url/origin.h"
 
 namespace media {
 
@@ -39,7 +38,6 @@
 // static
 void MojoCdm::Create(
     const std::string& key_system,
-    const url::Origin& security_origin,
     const CdmConfig& cdm_config,
     mojo::PendingRemote<mojom::ContentDecryptionModule> remote_cdm,
     const SessionMessageCB& session_message_cb,
@@ -55,8 +53,7 @@
   auto promise = std::make_unique<CdmInitializedPromise>(
       std::move(cdm_created_cb), mojo_cdm);
 
-  mojo_cdm->InitializeCdm(key_system, security_origin, cdm_config,
-                          std::move(promise));
+  mojo_cdm->InitializeCdm(key_system, cdm_config, std::move(promise));
 }
 
 MojoCdm::MojoCdm(mojo::PendingRemote<mojom::ContentDecryptionModule> remote_cdm,
@@ -103,7 +100,6 @@
 // error handler can't be invoked and callbacks won't be dispatched.
 
 void MojoCdm::InitializeCdm(const std::string& key_system,
-                            const url::Origin& security_origin,
                             const CdmConfig& cdm_config,
                             std::unique_ptr<CdmInitializedPromise> promise) {
   DVLOG(1) << __func__ << ": " << key_system;
@@ -127,7 +123,7 @@
   pending_init_promise_ = std::move(promise);
 
   remote_cdm_->Initialize(
-      key_system, security_origin, cdm_config,
+      key_system, cdm_config,
       base::BindOnce(&MojoCdm::OnCdmInitialized, base::Unretained(this)));
 }
 
diff --git a/media/mojo/clients/mojo_cdm.h b/media/mojo/clients/mojo_cdm.h
index 45f0fcb0..bee79ff 100644
--- a/media/mojo/clients/mojo_cdm.h
+++ b/media/mojo/clients/mojo_cdm.h
@@ -29,10 +29,6 @@
 class SingleThreadTaskRunner;
 }
 
-namespace url {
-class Origin;
-}
-
 namespace media {
 
 class MojoDecryptor;
@@ -48,7 +44,6 @@
 
   static void Create(
       const std::string& key_system,
-      const url::Origin& security_origin,
       const CdmConfig& cdm_config,
       mojo::PendingRemote<mojom::ContentDecryptionModule> remote_cdm,
       const SessionMessageCB& session_message_cb,
@@ -94,7 +89,6 @@
   ~MojoCdm() final;
 
   void InitializeCdm(const std::string& key_system,
-                     const url::Origin& security_origin,
                      const CdmConfig& cdm_config,
                      std::unique_ptr<CdmInitializedPromise> promise);
 
diff --git a/media/mojo/clients/mojo_cdm_factory.cc b/media/mojo/clients/mojo_cdm_factory.cc
index d606e735..2d04068f 100644
--- a/media/mojo/clients/mojo_cdm_factory.cc
+++ b/media/mojo/clients/mojo_cdm_factory.cc
@@ -15,7 +15,6 @@
 #include "media/mojo/clients/mojo_cdm.h"
 #include "media/mojo/mojom/interface_factory.mojom.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
-#include "url/origin.h"
 
 namespace media {
 
@@ -29,7 +28,6 @@
 
 void MojoCdmFactory::Create(
     const std::string& key_system,
-    const url::Origin& security_origin,
     const CdmConfig& cdm_config,
     const SessionMessageCB& session_message_cb,
     const SessionClosedCB& session_closed_cb,
@@ -38,13 +36,6 @@
     CdmCreatedCB cdm_created_cb) {
   DVLOG(2) << __func__ << ": " << key_system;
 
-  if (security_origin.opaque()) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(std::move(cdm_created_cb), nullptr, "Invalid origin."));
-    return;
-  }
-
   // If AesDecryptor can be used, always use it here in the local process.
   // Note: We should not run AesDecryptor in the browser process except for
   // testing. See http://crbug.com/441957.
@@ -63,9 +54,8 @@
   interface_factory_->CreateCdm(
       key_system, cdm_pending_remote.InitWithNewPipeAndPassReceiver());
 
-  MojoCdm::Create(key_system, security_origin, cdm_config,
-                  std::move(cdm_pending_remote), session_message_cb,
-                  session_closed_cb, session_keys_change_cb,
+  MojoCdm::Create(key_system, cdm_config, std::move(cdm_pending_remote),
+                  session_message_cb, session_closed_cb, session_keys_change_cb,
                   session_expiration_update_cb, std::move(cdm_created_cb));
 }
 
diff --git a/media/mojo/clients/mojo_cdm_factory.h b/media/mojo/clients/mojo_cdm_factory.h
index c3b8d05..0d987bc 100644
--- a/media/mojo/clients/mojo_cdm_factory.h
+++ b/media/mojo/clients/mojo_cdm_factory.h
@@ -21,7 +21,6 @@
 
   // CdmFactory implementation.
   void Create(const std::string& key_system,
-              const url::Origin& security_origin,
               const CdmConfig& cdm_config,
               const SessionMessageCB& session_message_cb,
               const SessionClosedCB& session_closed_cb,
diff --git a/media/mojo/clients/mojo_cdm_unittest.cc b/media/mojo/clients/mojo_cdm_unittest.cc
index f7b402b..99fd964 100644
--- a/media/mojo/clients/mojo_cdm_unittest.cc
+++ b/media/mojo/clients/mojo_cdm_unittest.cc
@@ -24,7 +24,6 @@
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
-#include "url/origin.h"
 
 using ::testing::_;
 using ::testing::DoAll;
@@ -48,7 +47,6 @@
 namespace {
 
 const char kClearKeyKeySystem[] = "org.w3.clearkey";
-const char kTestSecurityOrigin[] = "https://www.test.com";
 
 // Random key ID used to create a session.
 const uint8_t kKeyId[] = {
@@ -97,8 +95,8 @@
       }
     }
 
-    MojoCdm::Create(key_system, url::Origin::Create(GURL(kTestSecurityOrigin)),
-                    CdmConfig(), cdm_receiver_.BindNewPipeAndPassRemote(),
+    MojoCdm::Create(key_system, CdmConfig(),
+                    cdm_receiver_.BindNewPipeAndPassRemote(),
                     base::Bind(&MockCdmClient::OnSessionMessage,
                                base::Unretained(&cdm_client_)),
                     base::Bind(&MockCdmClient::OnSessionClosed,
@@ -125,8 +123,6 @@
     mojo_cdm_ = cdm;
     remote_cdm_ = cdm_factory_.GetCreatedCdm();
     EXPECT_EQ(kClearKeyKeySystem, remote_cdm_->GetKeySystem());
-    EXPECT_EQ(kTestSecurityOrigin,
-              remote_cdm_->GetSecurityOrigin().Serialize());
   }
 
   void ForceConnectionError() {
diff --git a/media/mojo/clients/mojo_renderer_unittest.cc b/media/mojo/clients/mojo_renderer_unittest.cc
index 5925bc6..f59e1be 100644
--- a/media/mojo/clients/mojo_renderer_unittest.cc
+++ b/media/mojo/clients/mojo_renderer_unittest.cc
@@ -33,7 +33,6 @@
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
-#include "url/origin.h"
 
 using ::base::test::RunCallback;
 using ::base::test::RunOnceCallback;
@@ -184,7 +183,6 @@
   void CreateCdm() {
     cdm_receiver_.Bind(cdm_remote_.BindNewPipeAndPassReceiver());
     cdm_remote_->Initialize(kClearKeyKeySystem,
-                            url::Origin::Create(GURL("https://www.test.com")),
                             CdmConfig(),
                             base::BindOnce(&MojoRendererTest::OnCdmCreated,
                                            base::Unretained(this)));
diff --git a/media/mojo/mojom/content_decryption_module.mojom b/media/mojo/mojom/content_decryption_module.mojom
index ca8d308..6cf1891 100644
--- a/media/mojo/mojom/content_decryption_module.mojom
+++ b/media/mojo/mojom/content_decryption_module.mojom
@@ -5,7 +5,6 @@
 module media.mojom;
 
 import "media/mojo/mojom/decryptor.mojom";
-import "url/mojom/origin.mojom";
 import "url/mojom/url.mojom";
 
 // See media::EmeInitDataType.
@@ -79,9 +78,7 @@
   // will be zero. Upon success, |cdm_id| will be non-zero and will later be
   // used to locate the CDM at the remote side. |decryptor| is the remote
   // Decryptor.
-  Initialize(string key_system,
-             url.mojom.Origin security_origin,
-             CdmConfig cdm_config)
+  Initialize(string key_system, CdmConfig cdm_config)
       => (CdmPromiseResult result, int32 cdm_id,
           pending_remote<Decryptor>? decryptor);
 
diff --git a/media/mojo/services/cdm_service_unittest.cc b/media/mojo/services/cdm_service_unittest.cc
index 02aec3d2..b98189d 100644
--- a/media/mojo/services/cdm_service_unittest.cc
+++ b/media/mojo/services/cdm_service_unittest.cc
@@ -17,7 +17,6 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
-#include "url/origin.h"
 
 namespace media {
 
@@ -33,7 +32,6 @@
 
 const char kClearKeyKeySystem[] = "org.w3.clearkey";
 const char kInvalidKeySystem[] = "invalid.key.system";
-const char kSecurityOrigin[] = "https://foo.com";
 
 class MockCdmServiceClient : public media::CdmService::Client {
  public:
@@ -99,10 +97,9 @@
         &CdmServiceTest::CdmConnectionClosed, base::Unretained(this)));
     EXPECT_CALL(*this, OnCdmInitialized(MatchesResult(expected_result), _, _))
         .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
-    cdm_remote_->Initialize(
-        key_system, url::Origin::Create(GURL(kSecurityOrigin)), CdmConfig(),
-        base::BindOnce(&CdmServiceTest::OnCdmInitialized,
-                       base::Unretained(this)));
+    cdm_remote_->Initialize(key_system, CdmConfig(),
+                            base::BindOnce(&CdmServiceTest::OnCdmInitialized,
+                                           base::Unretained(this)));
     run_loop.Run();
   }
 
diff --git a/media/mojo/services/media_service_unittest.cc b/media/mojo/services/media_service_unittest.cc
index b93d6c7b..085efa6 100644
--- a/media/mojo/services/media_service_unittest.cc
+++ b/media/mojo/services/media_service_unittest.cc
@@ -35,7 +35,6 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
-#include "url/origin.h"
 
 namespace media {
 
@@ -59,8 +58,6 @@
 const char kInvalidKeySystem[] = "invalid.key.system";
 #endif
 
-const char kSecurityOrigin[] = "https://foo.com";
-
 class MockRendererClient : public mojom::RendererClient {
  public:
   MockRendererClient() = default;
@@ -140,8 +137,7 @@
     // cdm_id" out and then call DoAll.
     EXPECT_CALL(*this, OnCdmInitialized(MatchesResult(expected_result), _, _))
         .WillOnce(WithArg<1>(DoAll(SaveArg<0>(&cdm_id), QuitLoop(&run_loop))));
-    cdm_->Initialize(key_system, url::Origin::Create(GURL(kSecurityOrigin)),
-                     CdmConfig(),
+    cdm_->Initialize(key_system, CdmConfig(),
                      base::BindOnce(&MediaServiceTest::OnCdmInitialized,
                                     base::Unretained(this)));
     run_loop.Run();
diff --git a/media/mojo/services/mojo_cdm_service.cc b/media/mojo/services/mojo_cdm_service.cc
index 16e60b8..ba20eea6 100644
--- a/media/mojo/services/mojo_cdm_service.cc
+++ b/media/mojo/services/mojo_cdm_service.cc
@@ -19,7 +19,6 @@
 #include "media/mojo/common/media_type_converters.h"
 #include "media/mojo/services/mojo_cdm_service_context.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
-#include "url/origin.h"
 
 namespace media {
 
@@ -58,7 +57,6 @@
 }
 
 void MojoCdmService::Initialize(const std::string& key_system,
-                                const url::Origin& security_origin,
                                 const CdmConfig& cdm_config,
                                 InitializeCallback callback) {
   DVLOG(1) << __func__ << ": " << key_system;
@@ -68,7 +66,7 @@
 
   auto weak_this = weak_factory_.GetWeakPtr();
   cdm_factory_->Create(
-      key_system, security_origin, cdm_config,
+      key_system, cdm_config,
       base::Bind(&MojoCdmService::OnSessionMessage, weak_this),
       base::Bind(&MojoCdmService::OnSessionClosed, weak_this),
       base::Bind(&MojoCdmService::OnSessionKeysChange, weak_this),
diff --git a/media/mojo/services/mojo_cdm_service.h b/media/mojo/services/mojo_cdm_service.h
index 20903a5..c38939f 100644
--- a/media/mojo/services/mojo_cdm_service.h
+++ b/media/mojo/services/mojo_cdm_service.h
@@ -47,7 +47,6 @@
       mojo::PendingAssociatedRemote<mojom::ContentDecryptionModuleClient>
           client) final;
   void Initialize(const std::string& key_system,
-                  const url::Origin& security_origin,
                   const CdmConfig& cdm_config,
                   InitializeCallback callback) final;
   void SetServerCertificate(const std::vector<uint8_t>& certificate_data,
diff --git a/media/mojo/services/mojo_media_client.h b/media/mojo/services/mojo_media_client.h
index 03263ee..0888eb39 100644
--- a/media/mojo/services/mojo_media_client.h
+++ b/media/mojo/services/mojo_media_client.h
@@ -42,6 +42,10 @@
     base::flat_map<VideoDecoderImplementation,
                    std::vector<SupportedVideoDecoderConfig>>;
 
+// Provides a way for MediaService to create concrete (e.g. platform specific)
+// media components’ implementations. When MediaService is created, a
+// MojoMediaClient must be passed in so that MediaService knows how to create
+// the media components.
 class MEDIA_MOJO_EXPORT MojoMediaClient {
  public:
   // Called before the host application is scheduled to quit.
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 6f5dfd1..c5206a3c 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -953,6 +953,8 @@
       "quiche/common/platform/impl/quiche_str_cat_impl.h",
       "quiche/common/platform/impl/quiche_string_piece_impl.h",
       "quiche/common/platform/impl/quiche_text_utils_impl.h",
+      "quiche/common/platform/impl/quiche_time_utils_impl.cc",
+      "quiche/common/platform/impl/quiche_time_utils_impl.h",
       "quiche/common/platform/impl/quiche_unordered_containers_impl.h",
       "socket/client_socket_factory.cc",
       "socket/client_socket_factory.h",
diff --git a/net/quiche/common/platform/impl/quiche_time_utils_impl.cc b/net/quiche/common/platform/impl/quiche_time_utils_impl.cc
new file mode 100644
index 0000000..7c78cbc
--- /dev/null
+++ b/net/quiche/common/platform/impl/quiche_time_utils_impl.cc
@@ -0,0 +1,50 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quiche/common/platform/impl/quiche_time_utils_impl.h"
+
+#include "base/time/time.h"
+
+#include <iostream>
+
+namespace quiche {
+QuicheOptional<int64_t> QuicheUtcDateTimeToUnixSecondsInner(int year,
+                                                            int month,
+                                                            int day,
+                                                            int hour,
+                                                            int minute,
+                                                            int second) {
+  base::Time::Exploded exploded{
+      year, month,
+      0,  // day_of_week
+      day,  hour,  minute, second,
+  };
+  base::Time time;
+  if (!base::Time::FromUTCExploded(exploded, &time)) {
+    return base::nullopt;
+  }
+  return (time - base::Time::UnixEpoch()).InSeconds();
+}
+
+QuicheOptional<int64_t> QuicheUtcDateTimeToUnixSecondsImpl(int year,
+                                                           int month,
+                                                           int day,
+                                                           int hour,
+                                                           int minute,
+                                                           int second) {
+  // Handle leap seconds without letting any other irregularities happen.
+  if (second == 60) {
+    auto previous_second = QuicheUtcDateTimeToUnixSecondsInner(
+        year, month, day, hour, minute, second - 1);
+    if (!previous_second.has_value()) {
+      return base::nullopt;
+    }
+    return *previous_second + 1;
+  }
+
+  return QuicheUtcDateTimeToUnixSecondsInner(year, month, day, hour, minute,
+                                             second);
+}
+
+}  // namespace quiche
diff --git a/net/quiche/common/platform/impl/quiche_time_utils_impl.h b/net/quiche/common/platform/impl/quiche_time_utils_impl.h
new file mode 100644
index 0000000..60dda04
--- /dev/null
+++ b/net/quiche/common/platform/impl/quiche_time_utils_impl.h
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_TIME_UTILS_IMPL_H_
+#define NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_TIME_UTILS_IMPL_H_
+
+#include <cstdint>
+
+#include "net/base/net_export.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
+
+namespace quiche {
+
+NET_EXPORT_PRIVATE QuicheOptional<int64_t> QuicheUtcDateTimeToUnixSecondsImpl(
+    int year,
+    int month,
+    int day,
+    int hour,
+    int minute,
+    int second);
+
+}  // namespace quiche
+
+#endif  // NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_TIME_UTILS_IMPL_H_
diff --git a/net/test/spawned_test_server/base_test_server.cc b/net/test/spawned_test_server/base_test_server.cc
index 92611d2..8330ccda5 100644
--- a/net/test/spawned_test_server/base_test_server.cc
+++ b/net/test/spawned_test_server/base_test_server.cc
@@ -363,15 +363,14 @@
 bool BaseTestServer::SetAndParseServerData(const std::string& server_data,
                                            int* port) {
   VLOG(1) << "Server data: " << server_data;
-  base::JSONReader json_reader;
-  base::Optional<base::Value> value(json_reader.ReadToValue(server_data));
-  if (!value || !value->is_dict()) {
-    LOG(ERROR) << "Could not parse server data: "
-               << json_reader.GetErrorMessage();
+  base::JSONReader::ValueWithError parsed_json =
+      base::JSONReader::ReadAndReturnValueWithError(server_data);
+  if (!parsed_json.value || !parsed_json.value->is_dict()) {
+    LOG(ERROR) << "Could not parse server data: " << parsed_json.error_message;
     return false;
   }
 
-  server_data_ = std::move(value);
+  server_data_ = std::move(parsed_json.value);
 
   base::Optional<int> port_value = server_data_->FindIntKey("port");
   if (!port_value) {
diff --git a/net/third_party/quiche/BUILD.gn b/net/third_party/quiche/BUILD.gn
index 201d6c1..180e75f 100644
--- a/net/third_party/quiche/BUILD.gn
+++ b/net/third_party/quiche/BUILD.gn
@@ -23,6 +23,7 @@
       "src/common/platform/api/quiche_str_cat.h",
       "src/common/platform/api/quiche_string_piece.h",
       "src/common/platform/api/quiche_text_utils.h",
+      "src/common/platform/api/quiche_time_utils.h",
       "src/common/platform/api/quiche_unordered_containers.h",
       "src/common/quiche_data_reader.cc",
       "src/common/quiche_data_reader.h",
@@ -1230,6 +1231,7 @@
     "src/common/platform/api/quiche_endian_test.cc",
     "src/common/platform/api/quiche_str_cat_test.cc",
     "src/common/platform/api/quiche_text_utils_test.cc",
+    "src/common/platform/api/quiche_time_utils_test.cc",
     "src/quic/core/congestion_control/bbr_sender_test.cc",
     "src/quic/core/congestion_control/cubic_bytes_test.cc",
     "src/quic/core/congestion_control/general_loss_algorithm_test.cc",
diff --git a/services/device/geolocation/geolocation_context.cc b/services/device/geolocation/geolocation_context.cc
index 379b765..a41139a 100644
--- a/services/device/geolocation/geolocation_context.cc
+++ b/services/device/geolocation/geolocation_context.cc
@@ -24,7 +24,8 @@
 }
 
 void GeolocationContext::BindGeolocation(
-    mojo::PendingReceiver<mojom::Geolocation> receiver) {
+    mojo::PendingReceiver<mojom::Geolocation> receiver,
+    const GURL& requesting_origin) {
   GeolocationImpl* impl = new GeolocationImpl(std::move(receiver), this);
   impls_.push_back(base::WrapUnique<GeolocationImpl>(impl));
   if (geoposition_override_)
diff --git a/services/device/geolocation/geolocation_context.h b/services/device/geolocation/geolocation_context.h
index d586379..b7c65a6 100644
--- a/services/device/geolocation/geolocation_context.h
+++ b/services/device/geolocation/geolocation_context.h
@@ -30,8 +30,8 @@
   static void Create(mojo::PendingReceiver<mojom::GeolocationContext> receiver);
 
   // mojom::GeolocationContext implementation:
-  void BindGeolocation(
-      mojo::PendingReceiver<mojom::Geolocation> receiver) override;
+  void BindGeolocation(mojo::PendingReceiver<mojom::Geolocation> receiver,
+                       const GURL& requesting_origin) override;
   void SetOverride(mojom::GeopositionPtr geoposition) override;
   void ClearOverride() override;
 
diff --git a/services/device/geolocation/geolocation_service_unittest.cc b/services/device/geolocation/geolocation_service_unittest.cc
index 52ebfee8e..70547aab 100644
--- a/services/device/geolocation/geolocation_service_unittest.cc
+++ b/services/device/geolocation/geolocation_service_unittest.cc
@@ -54,7 +54,7 @@
     device_service()->BindGeolocationContext(
         geolocation_context_.BindNewPipeAndPassReceiver());
     geolocation_context_->BindGeolocation(
-        geolocation_.BindNewPipeAndPassReceiver());
+        geolocation_.BindNewPipeAndPassReceiver(), GURL::EmptyGURL());
   }
 
   void TearDown() override {
diff --git a/services/device/public/cpp/test/scoped_geolocation_overrider.cc b/services/device/public/cpp/test/scoped_geolocation_overrider.cc
index 624edbc..c0bd2d5 100644
--- a/services/device/public/cpp/test/scoped_geolocation_overrider.cc
+++ b/services/device/public/cpp/test/scoped_geolocation_overrider.cc
@@ -39,8 +39,8 @@
   void OnDisconnect(FakeGeolocation* impl);
 
   // mojom::GeolocationContext implementation:
-  void BindGeolocation(
-      mojo::PendingReceiver<mojom::Geolocation> receiver) override;
+  void BindGeolocation(mojo::PendingReceiver<mojom::Geolocation> receiver,
+                       const GURL& requesting_origin) override;
   void SetOverride(mojom::GeopositionPtr geoposition) override;
   void ClearOverride() override;
 
@@ -194,7 +194,8 @@
 }
 
 void ScopedGeolocationOverrider::FakeGeolocationContext::BindGeolocation(
-    mojo::PendingReceiver<mojom::Geolocation> receiver) {
+    mojo::PendingReceiver<mojom::Geolocation> receiver,
+    const GURL& requesting_origin) {
   impls_.insert(std::make_unique<FakeGeolocation>(std::move(receiver), this));
 }
 
diff --git a/services/device/public/mojom/BUILD.gn b/services/device/public/mojom/BUILD.gn
index 6a3a2ae..221576f 100644
--- a/services/device/public/mojom/BUILD.gn
+++ b/services/device/public/mojom/BUILD.gn
@@ -37,6 +37,7 @@
     "//mojo/public/mojom/base",
     "//services/network/public/mojom",
     "//services/network/public/mojom:mutable_network_traffic_annotation_interface",
+    "//url/mojom:url_mojom_gurl",
   ]
 
   if (is_chromeos) {
diff --git a/services/device/public/mojom/geolocation_context.mojom b/services/device/public/mojom/geolocation_context.mojom
index 2123c45c..1917b33 100644
--- a/services/device/public/mojom/geolocation_context.mojom
+++ b/services/device/public/mojom/geolocation_context.mojom
@@ -6,13 +6,18 @@
 
 import "services/device/public/mojom/geolocation.mojom";
 import "services/device/public/mojom/geoposition.mojom";
+import "url/mojom/url.mojom";
 
 // GeolocationContext provides methods to bind Geolocation instance and to
 // set/clear overrides of geoposition that will apply to all Geolocation
 // instances created by this context.
 interface GeolocationContext {
   // Creates a Geolocation instance that is bound to the |request|.
-  BindGeolocation(pending_receiver<Geolocation> receiver);
+  // The |origin| is the origin of the top-level frame which the |request| from,
+  // it is only used for |InstalledWebappGeolocationContext| to separate request
+  // from different Trusted Web Activity client apps.
+  BindGeolocation(pending_receiver<Geolocation> receiver,
+                  url.mojom.Url origin);
 
   // Enables geolocation override. This method can be used to trigger possible
   // location-specific behavior in GeolocationImpl created by this
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
index 30bb273..bcc0f13 100644
--- a/services/network/cors/cors_url_loader.cc
+++ b/services/network/cors/cors_url_loader.cc
@@ -11,6 +11,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_split.h"
 #include "net/base/load_flags.h"
+#include "net/http/http_status_code.h"
 #include "services/network/cors/cors_url_loader_factory.h"
 #include "services/network/cors/preflight_controller.h"
 #include "services/network/public/cpp/cors/cors.h"
@@ -83,6 +84,19 @@
 
 constexpr const char kTimingAllowOrigin[] = "Timing-Allow-Origin";
 
+bool IsBodyNotNullAndSourceNull(const ResourceRequestBody* request_body) {
+  if (!request_body)
+    return false;
+  const std::vector<DataElement>* elements = request_body->elements();
+  if (elements->size() == 0u)
+    return false;
+  // https://fetch.spec.whatwg.org/#concept-bodyinit-extract
+  // Body's source is null means the body is not extracted from ReadableStream.
+  if (elements->size() > 1u)
+    return false;
+  return elements->at(0).type() == mojom::DataElementType::kChunkedDataPipe;
+}
+
 }  // namespace
 
 CorsURLLoader::CorsURLLoader(
@@ -215,6 +229,13 @@
   request_.method = redirect_info_.new_method;
   request_.referrer = GURL(redirect_info_.new_referrer);
   request_.referrer_policy = redirect_info_.new_referrer_policy;
+  request_.site_for_cookies = redirect_info_.new_site_for_cookies;
+
+  if (request_.trusted_params) {
+    request_.trusted_params->isolation_info =
+        request_.trusted_params->isolation_info.CreateForRedirect(
+            url::Origin::Create(request_.url));
+  }
 
   // The request method can be changed to "GET". In this case we need to
   // reset the request body manually.
@@ -358,10 +379,13 @@
     return;
   }
 
-  // TODO(yhirano): Implement the following (Note: this is needed when upload
-  // streaming is implemented):
   // If |actualResponse|’s status is not 303, |request|’s body is non-null, and
   // |request|’s body’s source is null, then return a network error.
+  if (redirect_info.status_code != net::HTTP_SEE_OTHER &&
+      IsBodyNotNullAndSourceNull(request_.request_body.get())) {
+    HandleComplete(URLLoaderCompletionStatus(net::ERR_INVALID_ARGUMENT));
+    return;
+  }
 
   // If |actualResponse|’s location URL’s origin is not same origin with
   // |request|’s current url’s origin and |request|’s origin is not same origin
diff --git a/services/network/cors/cors_url_loader_unittest.cc b/services/network/cors/cors_url_loader_unittest.cc
index f17163f..3d64f7e 100644
--- a/services/network/cors/cors_url_loader_unittest.cc
+++ b/services/network/cors/cors_url_loader_unittest.cc
@@ -333,13 +333,15 @@
       base::StringPiece method,
       const GURL& url,
       base::StringPiece referrer = base::StringPiece(),
-      ReferrerPolicy referrer_policy = net::URLRequest::NO_REFERRER) {
+      ReferrerPolicy referrer_policy = net::URLRequest::NO_REFERRER,
+      net::SiteForCookies site_for_cookies = net::SiteForCookies()) {
     net::RedirectInfo redirect_info;
     redirect_info.status_code = status_code;
     redirect_info.new_method = method.as_string();
     redirect_info.new_url = url;
     redirect_info.new_referrer = referrer.as_string();
     redirect_info.new_referrer_policy = referrer_policy;
+    redirect_info.new_site_for_cookies = site_for_cookies;
     return redirect_info;
   }
 
@@ -1161,9 +1163,11 @@
   RunUntilCreateLoaderAndStartCalled();
 
   EXPECT_EQ(1, num_created_loaders());
-  EXPECT_EQ(GetRequest().url, url);
-  EXPECT_EQ(GetRequest().method, "POST");
-  EXPECT_EQ(GetRequest().referrer, url);
+  EXPECT_EQ(url, GetRequest().url);
+  EXPECT_EQ("POST", GetRequest().method);
+  EXPECT_EQ(url, GetRequest().referrer);
+  EXPECT_EQ(net::URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN,
+            GetRequest().referrer_policy);
 
   NotifyLoaderClientOnReceiveRedirect(CreateRedirectInfo(
       303, "GET", new_url, "https://other.example.com",
@@ -1180,9 +1184,86 @@
   RunUntilCreateLoaderAndStartCalled();
 
   EXPECT_EQ(2, num_created_loaders());
-  EXPECT_EQ(GetRequest().url, new_url);
-  EXPECT_EQ(GetRequest().referrer, GURL("https://other.example.com"));
-  EXPECT_EQ(GetRequest().method, "GET");
+  EXPECT_EQ(new_url, GetRequest().url);
+  EXPECT_EQ("GET", GetRequest().method);
+  EXPECT_EQ(GURL("https://other.example.com"), GetRequest().referrer);
+  EXPECT_EQ(net::URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN,
+            GetRequest().referrer_policy);
+
+  NotifyLoaderClientOnReceiveResponse(
+      {{"Access-Control-Allow-Origin", "https://example.com"}});
+  NotifyLoaderClientOnComplete(net::OK);
+  RunUntilComplete();
+
+  EXPECT_FALSE(client().has_received_redirect());
+  EXPECT_TRUE(client().has_received_response());
+  EXPECT_TRUE(client().has_received_completion());
+  EXPECT_EQ(net::OK, client().completion_status().error_code);
+}
+
+// Makes sure that if an intercepted redirect updates the IsolationInfo and the
+// SiteForCookies values, the CorsURLLoader respects those changes. The former
+// only happens for frames, and the latter for subframes, but should make
+// assumptions about whether these need to be updated in CorsURLLoader.
+TEST_F(CorsURLLoaderTest,
+       InterceptedRedirectChangesIsolationInfoAndSiteForCookies) {
+  auto params = network::mojom::URLLoaderFactoryParams::New();
+  ResetFactory(base::nullopt, kRendererProcessId, true /* is_trusted */,
+               params->ignore_isolated_world_origin,
+               false /* skip_cors_enabled_scheme_check */);
+
+  const GURL url("https://example.com/foo.png");
+  const url::Origin url_origin = url::Origin::Create(url);
+  const net::SiteForCookies url_site_for_cookies =
+      net::SiteForCookies::FromOrigin(url_origin);
+
+  const GURL new_url("https://other.example.com/foo.png");
+  const url::Origin new_url_origin = url::Origin::Create(new_url);
+  const net::SiteForCookies new_url_site_for_cookies =
+      net::SiteForCookies::FromOrigin(new_url_origin);
+
+  ResourceRequest request;
+  request.mode = mojom::RequestMode::kCors;
+  request.credentials_mode = mojom::CredentialsMode::kOmit;
+  request.url = url;
+  request.request_initiator = url_origin;
+  request.site_for_cookies = url_site_for_cookies;
+  request.update_first_party_url_on_redirect = true;
+  request.trusted_params = ResourceRequest::TrustedParams();
+  request.trusted_params->isolation_info = net::IsolationInfo::Create(
+      net::IsolationInfo::RedirectMode::kUpdateTopFrame,
+      url_origin /* top_frame_origin */, url_origin /* frame_origin */,
+      url_site_for_cookies);
+  CreateLoaderAndStart(request);
+  RunUntilCreateLoaderAndStartCalled();
+
+  EXPECT_EQ(1, num_created_loaders());
+  EXPECT_EQ(url, GetRequest().url);
+
+  NotifyLoaderClientOnReceiveRedirect(CreateRedirectInfo(
+      303, "GET", new_url, "" /* referrer */, net::URLRequest::NO_REFERRER,
+      new_url_site_for_cookies));
+  RunUntilRedirectReceived();
+
+  EXPECT_TRUE(IsNetworkLoaderStarted());
+  EXPECT_FALSE(client().has_received_completion());
+  EXPECT_FALSE(client().has_received_response());
+  EXPECT_TRUE(client().has_received_redirect());
+
+  ClearHasReceivedRedirect();
+  FollowRedirect();
+  RunUntilCreateLoaderAndStartCalled();
+
+  EXPECT_EQ(2, num_created_loaders());
+  EXPECT_EQ(new_url, GetRequest().url);
+  EXPECT_EQ("GET", GetRequest().method);
+  EXPECT_TRUE(
+      GetRequest().site_for_cookies.IsEquivalent(new_url_site_for_cookies));
+  EXPECT_TRUE(GetRequest().trusted_params->isolation_info.IsEqualForTesting(
+      net::IsolationInfo::Create(
+          net::IsolationInfo::RedirectMode::kUpdateTopFrame,
+          new_url_origin /* top_frame_origin */,
+          new_url_origin /* frame_origin */, new_url_site_for_cookies)));
 
   NotifyLoaderClientOnReceiveResponse(
       {{"Access-Control-Allow-Origin", "https://example.com"}});
diff --git a/services/network/cors/preflight_controller.cc b/services/network/cors/preflight_controller.cc
index 24f48caf..1cae6a7 100644
--- a/services/network/cors/preflight_controller.cc
+++ b/services/network/cors/preflight_controller.cc
@@ -295,8 +295,14 @@
 
     if (!(original_request_.load_flags & net::LOAD_DISABLE_CACHE) &&
         !detected_error_status) {
+      const net::NetworkIsolationKey& network_isolation_key =
+          original_request_.trusted_params.has_value()
+              ? original_request_.trusted_params->isolation_info
+                    .network_isolation_key()
+              : net::NetworkIsolationKey();
       controller_->AppendToCache(*original_request_.request_initiator,
-                                 original_request_.url, std::move(result));
+                                 original_request_.url, network_isolation_key,
+                                 std::move(result));
     }
 
     std::move(completion_callback_)
@@ -400,11 +406,15 @@
     int32_t process_id) {
   DCHECK(request.request_initiator);
 
+  const net::NetworkIsolationKey& network_isolation_key =
+      request.trusted_params.has_value()
+          ? request.trusted_params->isolation_info.network_isolation_key()
+          : net::NetworkIsolationKey();
   if (!RetrieveCacheFlags(request.load_flags) && !request.is_external_request &&
       cache_.CheckIfRequestCanSkipPreflight(
-          request.request_initiator.value(), request.url,
-          net::NetworkIsolationKey::Todo(), request.credentials_mode,
-          request.method, request.headers, request.is_revalidating)) {
+          request.request_initiator.value(), request.url, network_isolation_key,
+          request.credentials_mode, request.method, request.headers,
+          request.is_revalidating)) {
     std::move(callback).Run(net::OK, base::nullopt);
     return;
   }
@@ -424,9 +434,9 @@
 void PreflightController::AppendToCache(
     const url::Origin& origin,
     const GURL& url,
+    const net::NetworkIsolationKey& network_isolation_key,
     std::unique_ptr<PreflightResult> result) {
-  cache_.AppendEntry(origin, url, net::NetworkIsolationKey::Todo(),
-                     std::move(result));
+  cache_.AppendEntry(origin, url, network_isolation_key, std::move(result));
 }
 
 }  // namespace cors
diff --git a/services/network/cors/preflight_controller.h b/services/network/cors/preflight_controller.h
index 737bfcab..8ee773e 100644
--- a/services/network/cors/preflight_controller.h
+++ b/services/network/cors/preflight_controller.h
@@ -84,6 +84,7 @@
   void RemoveLoader(PreflightLoader* loader);
   void AppendToCache(const url::Origin& origin,
                      const GURL& url,
+                     const net::NetworkIsolationKey& network_isolation_key,
                      std::unique_ptr<PreflightResult> result);
 
   NetworkService* network_service() { return network_service_; }
diff --git a/services/network/cors/preflight_controller_unittest.cc b/services/network/cors/preflight_controller_unittest.cc
index e659a03..619787b 100644
--- a/services/network/cors/preflight_controller_unittest.cc
+++ b/services/network/cors/preflight_controller_unittest.cc
@@ -343,7 +343,8 @@
   PreflightControllerTest()
       : task_environment_(base::test::TaskEnvironment::MainThreadType::IO),
         test_initiator_origin_(
-            url::Origin::Create(GURL("http://example.com/"))) {
+            url::Origin::Create(GURL("http://example.com/"))),
+        access_control_allow_origin_(test_initiator_origin_) {
     CorsURLLoaderFactory::SetAllowExternalPreflightsForTesting(true);
     mojo::Remote<mojom::NetworkService> network_service_remote;
     network_service_ = NetworkService::Create(
@@ -393,9 +394,16 @@
     run_loop_->Run();
   }
 
+  void SetAccessControlAllowOrigin(const url::Origin origin) {
+    access_control_allow_origin_ = origin;
+  }
+
   const url::Origin& test_initiator_origin() const {
     return test_initiator_origin_;
   }
+  const url::Origin& access_control_allow_origin() const {
+    return access_control_allow_origin_;
+  }
   int net_error() const { return net_error_; }
   base::Optional<CorsErrorStatus> status() { return status_; }
   base::Optional<CorsErrorStatus> success() { return base::nullopt; }
@@ -404,6 +412,8 @@
 
  private:
   void SetUp() override {
+    SetAccessControlAllowOrigin(test_initiator_origin_);
+
     preflight_controller_ = std::make_unique<PreflightController>(
         std::vector<std::string>(), network_service_.get());
 
@@ -430,7 +440,7 @@
       const url::Origin origin =
           net::test_server::ShouldHandle(request, "/tainted")
               ? url::Origin()
-              : test_initiator_origin();
+              : access_control_allow_origin();
       response->AddCustomHeader(header_names::kAccessControlAllowOrigin,
                                 origin.Serialize());
       response->AddCustomHeader(header_names::kAccessControlAllowMethods,
@@ -445,6 +455,7 @@
 
   base::test::TaskEnvironment task_environment_;
   const url::Origin test_initiator_origin_;
+  url::Origin access_control_allow_origin_;
   std::unique_ptr<base::RunLoop> run_loop_;
 
   std::unique_ptr<NetworkService> network_service_;
@@ -510,6 +521,41 @@
   EXPECT_EQ(4u, access_count());
 }
 
+TEST_F(PreflightControllerTest, CheckRequestNetworkIsolationKey) {
+  ResourceRequest request;
+  request.mode = mojom::RequestMode::kCors;
+  request.credentials_mode = mojom::CredentialsMode::kOmit;
+  request.url = GetURL("/allow");
+  const url::Origin& origin = test_initiator_origin();
+  request.request_initiator = origin;
+  ResourceRequest::TrustedParams trusted_params;
+  trusted_params.isolation_info = net::IsolationInfo::Create(
+      net::IsolationInfo::RedirectMode::kUpdateNothing, origin, origin,
+      net::SiteForCookies());
+  request.trusted_params = {trusted_params};
+
+  PerformPreflightCheck(request);
+  EXPECT_EQ(net::OK, net_error());
+  ASSERT_FALSE(status());
+  EXPECT_EQ(1u, access_count());
+
+  PerformPreflightCheck(request);
+  EXPECT_EQ(net::OK, net_error());
+  ASSERT_FALSE(status());
+  EXPECT_EQ(1u, access_count());  // Should be from the preflight cache.
+
+  url::Origin second_origin = url::Origin::Create(GURL("https://example.com/"));
+  request.request_initiator = second_origin;
+  SetAccessControlAllowOrigin(second_origin);
+  request.trusted_params->isolation_info = net::IsolationInfo::Create(
+      net::IsolationInfo::RedirectMode::kUpdateNothing, origin, second_origin,
+      net::SiteForCookies());
+  PerformPreflightCheck(request);
+  EXPECT_EQ(net::OK, net_error());
+  ASSERT_FALSE(status());
+  EXPECT_EQ(2u, access_count());
+}
+
 TEST_F(PreflightControllerTest, CheckTaintedRequest) {
   ResourceRequest request;
   request.mode = mojom::RequestMode::kCors;
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 758ea1a..01323f3 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -6603,15 +6603,11 @@
   my_request.trust_token_params =
       OptionalTrustTokenParams(mojom::TrustTokenParams::New());
 
-  auto factory_params = mojom::URLLoaderFactoryParams::New();
-  factory_params->top_frame_origin =
-      url::Origin::Create(GURL("https://topframe.com/"));
-
   // Since the request doesn't have a destination URL suitable for use as a
   // Trust Tokens issuer, it should fail.
-  std::unique_ptr<TestURLLoaderClient> client =
-      FetchRequest(my_request, network_context.get(), mojom::kURLLoadOptionNone,
-                   mojom::kBrowserProcessId, std::move(factory_params));
+  std::unique_ptr<TestURLLoaderClient> client = FetchRequest(
+      my_request, network_context.get(), mojom::kURLLoadOptionNone,
+      mojom::kBrowserProcessId, mojom::URLLoaderFactoryParams::New());
   EXPECT_EQ(client->completion_status().error_code,
             net::ERR_TRUST_TOKEN_OPERATION_FAILED);
   EXPECT_EQ(client->completion_status().trust_token_operation_status,
@@ -6639,13 +6635,9 @@
   my_request.trust_token_params =
       OptionalTrustTokenParams(mojom::TrustTokenParams::New());
 
-  auto factory_params = mojom::URLLoaderFactoryParams::New();
-  factory_params->top_frame_origin =
-      url::Origin::Create(GURL("https://topframe.com/"));
-
-  std::unique_ptr<TestURLLoaderClient> client =
-      FetchRequest(my_request, network_context.get(), mojom::kURLLoadOptionNone,
-                   mojom::kBrowserProcessId, std::move(factory_params));
+  std::unique_ptr<TestURLLoaderClient> client = FetchRequest(
+      my_request, network_context.get(), mojom::kURLLoadOptionNone,
+      mojom::kBrowserProcessId, mojom::URLLoaderFactoryParams::New());
   EXPECT_EQ(client->completion_status().error_code,
             net::ERR_TRUST_TOKEN_OPERATION_FAILED);
   EXPECT_EQ(client->completion_status().trust_token_operation_status,
diff --git a/services/network/public/mojom/cross_origin_opener_policy.mojom b/services/network/public/mojom/cross_origin_opener_policy.mojom
index 88742651..ac96351b 100644
--- a/services/network/public/mojom/cross_origin_opener_policy.mojom
+++ b/services/network/public/mojom/cross_origin_opener_policy.mojom
@@ -4,6 +4,29 @@
 
 module network.mojom;
 
+import "url/mojom/url.mojom";
+
+// Reports potential COOP violations. Implemented in the browser process.
+// TODO(ahemery, pmeuleman): Add extra coop breakage cases as listed in
+// https://docs.google.com/document/d/1zWqwI8PFrezwQpBSejIMUfdtsIYl9-h8epasdrDXVIM/edit
+interface CrossOriginOpenerPolicyReporter {
+
+  // When COOP triggers a browsing context group swap during a navigation, we
+  // lose the existing opener, which can create page breakage. We report such
+  // cases using this function.
+  // |is_reported_from_document| is true if the report is coming from the
+  // document begin navigated from. It is false if the report originates from
+  // the document we are navigating to.
+  // |is_report_only| is true if we are reporting a breakage that would have
+  // occurred if we enforced the reporting only values of COOP.
+  QueueOpenerBreakageReport(url.mojom.Url other_url,
+                            bool is_reported_from_document,
+                            bool is_report_only);
+
+  // Connects a new pipe to this instance.
+  Clone(pending_receiver<CrossOriginOpenerPolicyReporter> receiver);
+};
+
 // Cross-Origin-Opener-Policy enum representing parsed values.
 enum CrossOriginOpenerPolicyValue {
   // Severs the opener relationship with openers/opened documents that are not
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index fef7927..1b7e84ec 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -604,10 +604,6 @@
   // 2) Make this an *origin* lock (rather than a *site* lock).
   url.mojom.Origin? request_initiator_site_lock;
 
-  // For subresource requests from frames, |top_frame_origin| is the request's
-  // top frame's origin.
-  url.mojom.Origin? top_frame_origin;
-
   // Cross-origin read blocking (CORB) configuration.
   bool is_corb_enabled = true;
 
diff --git a/storage/browser/database/database_quota_client.cc b/storage/browser/database/database_quota_client.cc
index 3d2cd6d..cff9601 100644
--- a/storage/browser/database/database_quota_client.cc
+++ b/storage/browser/database/database_quota_client.cc
@@ -98,10 +98,6 @@
   }
 }
 
-storage::QuotaClientType DatabaseQuotaClient::type() const {
-  return storage::QuotaClientType::kDatabase;
-}
-
 void DatabaseQuotaClient::OnQuotaManagerDestroyed() {}
 
 void DatabaseQuotaClient::GetOriginUsage(const url::Origin& origin,
diff --git a/storage/browser/database/database_quota_client.h b/storage/browser/database/database_quota_client.h
index 12375de9..4a8e642 100644
--- a/storage/browser/database/database_quota_client.h
+++ b/storage/browser/database/database_quota_client.h
@@ -30,7 +30,6 @@
   explicit DatabaseQuotaClient(scoped_refptr<DatabaseTracker> tracker);
 
   // QuotaClient method overrides
-  storage::QuotaClientType type() const override;
   void OnQuotaManagerDestroyed() override;
   void GetOriginUsage(const url::Origin& origin,
                       blink::mojom::StorageType type,
diff --git a/storage/browser/database/database_tracker.cc b/storage/browser/database/database_tracker.cc
index ecc6a0d..1e37e4de 100644
--- a/storage/browser/database/database_tracker.cc
+++ b/storage/browser/database/database_tracker.cc
@@ -22,6 +22,7 @@
 #include "storage/browser/database/database_quota_client.h"
 #include "storage/browser/database/database_util.h"
 #include "storage/browser/database/databases_table.h"
+#include "storage/browser/quota/quota_client_type.h"
 #include "storage/browser/quota/quota_manager_proxy.h"
 #include "storage/browser/quota/special_storage_policy.h"
 #include "storage/common/database/database_identifier.h"
@@ -101,7 +102,8 @@
            base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) {
   if (quota_manager_proxy) {
     quota_manager_proxy->RegisterClient(
-        base::MakeRefCounted<DatabaseQuotaClient>(this));
+        base::MakeRefCounted<DatabaseQuotaClient>(this),
+        QuotaClientType::kDatabase);
   }
 }
 
diff --git a/storage/browser/database/database_tracker_unittest.cc b/storage/browser/database/database_tracker_unittest.cc
index 5293254e..fc9c4f731 100644
--- a/storage/browser/database/database_tracker_unittest.cc
+++ b/storage/browser/database/database_tracker_unittest.cc
@@ -22,6 +22,7 @@
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
 #include "storage/browser/database/database_tracker.h"
+#include "storage/browser/quota/quota_client_type.h"
 #include "storage/browser/quota/quota_manager_proxy.h"
 #include "storage/browser/test/mock_special_storage_policy.h"
 #include "storage/common/database/database_identifier.h"
@@ -100,7 +101,8 @@
   TestQuotaManagerProxy()
       : QuotaManagerProxy(nullptr, nullptr), registered_client_(nullptr) {}
 
-  void RegisterClient(scoped_refptr<QuotaClient> client) override {
+  void RegisterClient(scoped_refptr<QuotaClient> client,
+                      QuotaClientType client_type) override {
     EXPECT_FALSE(registered_client_);
     registered_client_ = client;
   }
diff --git a/storage/browser/file_system/file_system_context.cc b/storage/browser/file_system/file_system_context.cc
index 84774d80..baea9c48 100644
--- a/storage/browser/file_system/file_system_context.cc
+++ b/storage/browser/file_system/file_system_context.cc
@@ -189,7 +189,8 @@
   if (quota_manager_proxy) {
     // Quota client assumes all backends have registered.
     quota_manager_proxy->RegisterClient(
-        base::MakeRefCounted<FileSystemQuotaClient>(this));
+        base::MakeRefCounted<FileSystemQuotaClient>(this),
+        QuotaClientType::kFileSystem);
   }
 
   sandbox_backend_->Initialize(this);
diff --git a/storage/browser/file_system/file_system_quota_client.cc b/storage/browser/file_system/file_system_quota_client.cc
index 66a30071..e6f7382 100644
--- a/storage/browser/file_system/file_system_quota_client.cc
+++ b/storage/browser/file_system/file_system_quota_client.cc
@@ -96,10 +96,6 @@
 
 FileSystemQuotaClient::~FileSystemQuotaClient() = default;
 
-QuotaClientType FileSystemQuotaClient::type() const {
-  return QuotaClientType::kFileSystem;
-}
-
 void FileSystemQuotaClient::GetOriginUsage(const url::Origin& origin,
                                            StorageType storage_type,
                                            GetUsageCallback callback) {
diff --git a/storage/browser/file_system/file_system_quota_client.h b/storage/browser/file_system/file_system_quota_client.h
index 01afe9e..df13c5a 100644
--- a/storage/browser/file_system/file_system_quota_client.h
+++ b/storage/browser/file_system/file_system_quota_client.h
@@ -37,7 +37,6 @@
   explicit FileSystemQuotaClient(FileSystemContext* file_system_context);
 
   // QuotaClient methods.
-  QuotaClientType type() const override;
   void OnQuotaManagerDestroyed() override {}
   void GetOriginUsage(const url::Origin& origin,
                       blink::mojom::StorageType type,
diff --git a/storage/browser/quota/quota_client.h b/storage/browser/quota/quota_client.h
index 642f52e..183edb5 100644
--- a/storage/browser/quota/quota_client.h
+++ b/storage/browser/quota/quota_client.h
@@ -36,8 +36,6 @@
   using DeletionCallback =
       base::OnceCallback<void(blink::mojom::QuotaStatusCode status)>;
 
-  virtual QuotaClientType type() const = 0;
-
   // Called when the QuotaManager is destroyed.
   virtual void OnQuotaManagerDestroyed() = 0;
 
diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc
index 4832836b..1b4bc91 100644
--- a/storage/browser/quota/quota_manager.cc
+++ b/storage/browser/quota/quota_manager.cc
@@ -551,11 +551,13 @@
     error_count_ = 0;
     remaining_clients_ = manager()->clients_.size();
     for (const auto& client : manager()->clients_) {
-      if (quota_client_types_.contains(client->type())) {
+      DCHECK(manager()->client_types_.contains(client.get()));
+      QuotaClientType client_type = manager()->client_types_[client.get()];
+      if (quota_client_types_.contains(client_type)) {
         static int tracing_id = 0;
         TRACE_EVENT_ASYNC_BEGIN2(
             "browsing_data", "QuotaManager::OriginDataDeleter", ++tracing_id,
-            "client_type", client->type(), "origin", origin_.Serialize());
+            "client_type", client_type, "origin", origin_.Serialize());
         client->DeleteOriginData(
             origin_, type_,
             base::BindOnce(&OriginDataDeleter::DidDeleteOriginData,
@@ -734,7 +736,9 @@
     // This may synchronously trigger |callback_| at the end of the for loop,
     // make sure we do nothing after this block.
     for (const auto& client : manager()->clients_) {
-      if (quota_client_types_.contains(client->type())) {
+      DCHECK(manager()->client_types_.contains(client.get()));
+      QuotaClientType client_type = manager()->client_types_[client.get()];
+      if (quota_client_types_.contains(client_type)) {
         client->PerformStorageCleanup(type_, barrier);
       } else {
         barrier.Run();
@@ -1215,16 +1219,18 @@
     return false;
   switch (type) {
     case StorageType::kTemporary:
-      temporary_usage_tracker_ = std::make_unique<UsageTracker>(
-          clients_, StorageType::kTemporary, special_storage_policy_.get());
+      temporary_usage_tracker_ =
+          std::make_unique<UsageTracker>(client_types_, StorageType::kTemporary,
+                                         special_storage_policy_.get());
       return true;
     case StorageType::kPersistent:
       persistent_usage_tracker_ = std::make_unique<UsageTracker>(
-          clients_, StorageType::kPersistent, special_storage_policy_.get());
+          client_types_, StorageType::kPersistent,
+          special_storage_policy_.get());
       return true;
     case StorageType::kSyncable:
       syncable_usage_tracker_ = std::make_unique<UsageTracker>(
-          clients_, StorageType::kSyncable, special_storage_policy_.get());
+          client_types_, StorageType::kSyncable, special_storage_policy_.get());
       return true;
     default:
       NOTREACHED();
@@ -1259,11 +1265,11 @@
                     : profile_path_.AppendASCII(kDatabaseName));
 
   temporary_usage_tracker_ = std::make_unique<UsageTracker>(
-      clients_, StorageType::kTemporary, special_storage_policy_.get());
+      client_types_, StorageType::kTemporary, special_storage_policy_.get());
   persistent_usage_tracker_ = std::make_unique<UsageTracker>(
-      clients_, StorageType::kPersistent, special_storage_policy_.get());
+      client_types_, StorageType::kPersistent, special_storage_policy_.get());
   syncable_usage_tracker_ = std::make_unique<UsageTracker>(
-      clients_, StorageType::kSyncable, special_storage_policy_.get());
+      client_types_, StorageType::kSyncable, special_storage_policy_.get());
 
   if (!is_incognito_) {
     histogram_timer_.Start(
@@ -1310,9 +1316,14 @@
   GetLRUOrigin(StorageType::kTemporary, std::move(did_get_origin_callback));
 }
 
-void QuotaManager::RegisterClient(scoped_refptr<QuotaClient> client) {
+void QuotaManager::RegisterClient(scoped_refptr<QuotaClient> client,
+                                  QuotaClientType client_type) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(!database_.get());
+  DCHECK(!database_.get())
+      << "All clients must be registered before the database is initialized";
+  DCHECK(client.get());
+
+  client_types_.insert({client.get(), client_type});
   clients_.push_back(std::move(client));
 }
 
diff --git a/storage/browser/quota/quota_manager.h b/storage/browser/quota/quota_manager.h
index 7554d36..71125c1d 100644
--- a/storage/browser/quota/quota_manager.h
+++ b/storage/browser/quota/quota_manager.h
@@ -150,36 +150,40 @@
       blink::mojom::StorageType type,
       UsageAndQuotaWithBreakdownCallback callback);
 
-  // Called by StorageClients.
-  // This method is declared as virtual to allow test code to override it.
+  // Called by storage backends.
   //
   // For UnlimitedStorage origins, this version skips usage and quota handling
-  // to avoid extra query cost.
-  // Do not call this method for apps/user-facing code.
+  // to avoid extra query cost. Do not call this method for apps/user-facing
+  // code.
+  //
+  // This method is declared as virtual to allow test code to override it.
   virtual void GetUsageAndQuota(const url::Origin& origin,
                                 blink::mojom::StorageType type,
                                 UsageAndQuotaCallback callback);
 
-  // Called by clients via proxy.
-  // Client storage should call this method when storage is accessed.
-  // Used to maintain LRU ordering.
+  // Called by storage backends via proxy.
+  //
+  // Quota-managed storage backends should call this method when storage is
+  // accessed. Used to maintain LRU ordering.
   void NotifyStorageAccessed(const url::Origin& origin,
                              blink::mojom::StorageType type);
 
-  // Called by clients via proxy.
-  // Client storage must call this method whenever they have made any
-  // modifications that change the amount of data stored in their storage.
+  // Called by storage backends via proxy.
+  //
+  // Quota-managed storage backends must call this method when they have made
+  // any modifications that change the amount of data stored in their storage.
   void NotifyStorageModified(QuotaClientType client_id,
                              const url::Origin& origin,
                              blink::mojom::StorageType type,
                              int64_t delta);
 
-  // Called by clients via proxy.
-  // This method is declared as virtual to allow test code to override it.
+  // Called by storage backends via proxy.
   //
   // Client storage must call this method whenever they run into disk
   // write errors. Used as a hint to determine if the storage partition is out
   // of space, and trigger actions if deemed appropriate.
+  //
+  // This method is declared as virtual to allow test code to override it.
   virtual void NotifyWriteFailed(const url::Origin& origin);
 
   // Used to avoid evicting origins with open pages.
@@ -315,10 +319,10 @@
     StatusCallback evict_origin_data_callback;
   };
 
-  // This initialization method is lazily called on the IO thread
-  // when the first quota manager API is called.
-  // Initialize must be called after all quota clients are added to the
-  // manager by RegisterStorage.
+  // Lazily called on the IO thread when the first quota manager API is called.
+  //
+  // Initialize() must be called after all quota clients are added to the
+  // manager by RegisterClient.
   void LazyInitialize();
   void FinishLazyInitialize(bool is_database_bootstraped);
   void BootstrapDatabaseForEviction(GetOriginCallback did_get_origin_callback,
@@ -329,7 +333,8 @@
 
   // Called by clients via proxy.
   // Registers a quota client to the manager.
-  void RegisterClient(scoped_refptr<QuotaClient> client);
+  void RegisterClient(scoped_refptr<QuotaClient> client,
+                      QuotaClientType client_type);
 
   UsageTracker* GetUsageTracker(blink::mojom::StorageType type) const;
 
@@ -455,7 +460,13 @@
   GetOriginCallback lru_origin_callback_;
   std::set<url::Origin> access_notified_origins_;
 
+  // Owns the QuotaClient instances registered via RegisterClient().
   std::vector<scoped_refptr<QuotaClient>> clients_;
+  // Maps QuotaClient instances to client types.
+  //
+  // The QuotaClient instances pointed to by the map keys are guaranteed to be
+  // alive, because they are owned by |clients_|.
+  base::flat_map<QuotaClient*, QuotaClientType> client_types_;
 
   std::unique_ptr<UsageTracker> temporary_usage_tracker_;
   std::unique_ptr<UsageTracker> persistent_usage_tracker_;
diff --git a/storage/browser/quota/quota_manager_proxy.cc b/storage/browser/quota/quota_manager_proxy.cc
index 8925660..92fa9ac 100644
--- a/storage/browser/quota/quota_manager_proxy.cc
+++ b/storage/browser/quota/quota_manager_proxy.cc
@@ -13,6 +13,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task_runner_util.h"
+#include "storage/browser/quota/quota_client_type.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 
 namespace storage {
@@ -36,16 +37,17 @@
 
 }  // namespace
 
-void QuotaManagerProxy::RegisterClient(scoped_refptr<QuotaClient> client) {
+void QuotaManagerProxy::RegisterClient(scoped_refptr<QuotaClient> client,
+                                       QuotaClientType client_type) {
   if (!io_thread_->BelongsToCurrentThread() &&
       io_thread_->PostTask(
           FROM_HERE, base::BindOnce(&QuotaManagerProxy::RegisterClient, this,
-                                    std::move(client)))) {
+                                    std::move(client), client_type))) {
     return;
   }
 
   if (manager_)
-    manager_->RegisterClient(std::move(client));
+    manager_->RegisterClient(std::move(client), client_type);
   else
     client->OnQuotaManagerDestroyed();
 }
diff --git a/storage/browser/quota/quota_manager_proxy.h b/storage/browser/quota/quota_manager_proxy.h
index 2d1cfee7..59fee6c4 100644
--- a/storage/browser/quota/quota_manager_proxy.h
+++ b/storage/browser/quota/quota_manager_proxy.h
@@ -18,6 +18,7 @@
 #include "base/sequenced_task_runner_helpers.h"
 #include "storage/browser/quota/quota_callbacks.h"
 #include "storage/browser/quota/quota_client.h"
+#include "storage/browser/quota/quota_client_type.h"
 #include "storage/browser/quota/quota_database.h"
 #include "storage/browser/quota/quota_manager.h"
 #include "storage/browser/quota/quota_task.h"
@@ -38,7 +39,8 @@
  public:
   using UsageAndQuotaCallback = QuotaManager::UsageAndQuotaCallback;
 
-  virtual void RegisterClient(scoped_refptr<QuotaClient> client);
+  virtual void RegisterClient(scoped_refptr<QuotaClient> client,
+                              QuotaClientType client_type);
   virtual void NotifyStorageAccessed(const url::Origin& origin,
                                      blink::mojom::StorageType type);
   virtual void NotifyStorageModified(QuotaClientType client_id,
diff --git a/storage/browser/quota/quota_manager_unittest.cc b/storage/browser/quota/quota_manager_unittest.cc
index e64135a..a6c997ce 100644
--- a/storage/browser/quota/quota_manager_unittest.cc
+++ b/storage/browser/quota/quota_manager_unittest.cc
@@ -117,7 +117,7 @@
       QuotaClientType client_type) {
     MockQuotaClient* client =
         new MockQuotaClient(quota_manager_->proxy(), mock_data, client_type);
-    quota_manager_->proxy()->RegisterClient(client);
+    quota_manager_->proxy()->RegisterClient(client, client_type);
     return client;
   }
 
diff --git a/storage/browser/quota/usage_tracker.cc b/storage/browser/quota/usage_tracker.cc
index 319dece..faf8fa2 100644
--- a/storage/browser/quota/usage_tracker.cc
+++ b/storage/browser/quota/usage_tracker.cc
@@ -12,6 +12,7 @@
 #include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "storage/browser/quota/client_usage_tracker.h"
+#include "storage/browser/quota/quota_client_type.h"
 
 namespace storage {
 
@@ -44,17 +45,24 @@
 };
 
 UsageTracker::UsageTracker(
-    const std::vector<scoped_refptr<QuotaClient>>& clients,
+    const base::flat_map<QuotaClient*, QuotaClientType>& client_types,
     blink::mojom::StorageType type,
     SpecialStoragePolicy* special_storage_policy)
     : type_(type) {
-  for (const auto& client : clients) {
-    if (client->DoesSupport(type)) {
-      client_tracker_map_[client->type()] =
-          std::make_unique<ClientUsageTracker>(this, client, type,
-                                               special_storage_policy);
-    }
+  size_t client_count = 0;
+
+  for (const auto& client_and_type : client_types) {
+    QuotaClient* client = client_and_type.first;
+    if (!client->DoesSupport(type))
+      continue;
+
+    QuotaClientType client_type = client_and_type.second;
+    client_tracker_map_[client_type].push_back(
+        std::make_unique<ClientUsageTracker>(this, client, type,
+                                             special_storage_policy));
+    ++client_count;
   }
+  client_count_ = client_count;
 }
 
 UsageTracker::~UsageTracker() {
@@ -86,8 +94,10 @@
       base::BindRepeating(&UsageTracker::AccumulateClientGlobalLimitedUsage,
                           weak_factory_.GetWeakPtr(), base::Owned(info));
 
-  for (const auto& client_type_and_tracker : client_tracker_map_)
-    client_type_and_tracker.second->GetGlobalLimitedUsage(accumulator);
+  for (const auto& client_type_and_trackers : client_tracker_map_) {
+    for (const auto& client_tracker : client_type_and_trackers.second)
+      client_tracker->GetGlobalLimitedUsage(accumulator);
+  }
 
   // Fire the sentinel as we've now called GetGlobalUsage for all clients.
   accumulator.Run(0);
@@ -112,8 +122,10 @@
       base::BindRepeating(&UsageTracker::AccumulateClientGlobalUsage,
                           weak_factory_.GetWeakPtr(), base::Owned(info));
 
-  for (const auto& client_type_and_tracker : client_tracker_map_)
-    client_type_and_tracker.second->GetGlobalUsage(accumulator);
+  for (const auto& client_type_and_trackers : client_tracker_map_) {
+    for (const auto& client_tracker : client_type_and_trackers.second)
+      client_tracker->GetGlobalUsage(accumulator);
+  }
 
   // Fire the sentinel as we've now called GetGlobalUsage for all clients.
   accumulator.Run(0, 0);
@@ -144,11 +156,13 @@
       base::BindOnce(&UsageTracker::FinallySendHostUsageWithBreakdown,
                      weak_factory_.GetWeakPtr(), base::Owned(info), host));
 
-  for (const auto& client_type_and_tracker : client_tracker_map_) {
-    client_type_and_tracker.second->GetHostUsage(
-        host, base::BindOnce(&UsageTracker::AccumulateClientHostUsage,
-                             weak_factory_.GetWeakPtr(), barrier, info, host,
-                             client_type_and_tracker.first));
+  for (const auto& client_type_and_trackers : client_tracker_map_) {
+    for (const auto& client_tracker : client_type_and_trackers.second) {
+      client_tracker->GetHostUsage(
+          host, base::BindOnce(&UsageTracker::AccumulateClientHostUsage,
+                               weak_factory_.GetWeakPtr(), barrier, info, host,
+                               client_type_and_trackers.first));
+    }
   }
 }
 
@@ -157,26 +171,30 @@
                                     int64_t delta) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(client_tracker_map_.count(client_type));
-  ClientUsageTracker* client_tracker = client_tracker_map_[client_type].get();
-  client_tracker->UpdateUsageCache(origin, delta);
+  for (const auto& client_tracker : client_tracker_map_[client_type])
+    client_tracker->UpdateUsageCache(origin, delta);
 }
 
 int64_t UsageTracker::GetCachedUsage() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   int64_t usage = 0;
-  for (const auto& client_type_and_tracker : client_tracker_map_)
-    usage += client_type_and_tracker.second->GetCachedUsage();
+  for (const auto& client_type_and_trackers : client_tracker_map_) {
+    for (const auto& client_tracker : client_type_and_trackers.second)
+      usage += client_tracker->GetCachedUsage();
+  }
   return usage;
 }
 
 std::map<std::string, int64_t> UsageTracker::GetCachedHostsUsage() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   std::map<std::string, int64_t> host_usage;
-  for (const auto& client_type_and_tracker : client_tracker_map_) {
-    std::map<std::string, int64_t> client_host_usage =
-        client_type_and_tracker.second->GetCachedHostsUsage();
-    for (const auto& host_and_usage : client_host_usage)
-      host_usage[host_and_usage.first] += host_and_usage.second;
+  for (const auto& client_type_and_trackers : client_tracker_map_) {
+    for (const auto& client_tracker : client_type_and_trackers.second) {
+      std::map<std::string, int64_t> client_host_usage =
+          client_tracker->GetCachedHostsUsage();
+      for (const auto& host_and_usage : client_host_usage)
+        host_usage[host_and_usage.first] += host_and_usage.second;
+    }
   }
   return host_usage;
 }
@@ -184,11 +202,13 @@
 std::map<url::Origin, int64_t> UsageTracker::GetCachedOriginsUsage() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   std::map<url::Origin, int64_t> origin_usage;
-  for (const auto& client_type_and_tracker : client_tracker_map_) {
-    std::map<url::Origin, int64_t> client_origin_usage =
-        client_type_and_tracker.second->GetCachedOriginsUsage();
-    for (const auto& origin_and_usage : client_origin_usage)
-      origin_usage[origin_and_usage.first] += origin_and_usage.second;
+  for (const auto& client_type_and_trackers : client_tracker_map_) {
+    for (const auto& client_tracker : client_type_and_trackers.second) {
+      std::map<url::Origin, int64_t> client_origin_usage =
+          client_tracker->GetCachedOriginsUsage();
+      for (const auto& origin_and_usage : client_origin_usage)
+        origin_usage[origin_and_usage.first] += origin_and_usage.second;
+    }
   }
   return origin_usage;
 }
@@ -196,11 +216,12 @@
 std::set<url::Origin> UsageTracker::GetCachedOrigins() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   std::set<url::Origin> origins;
-  for (const auto& client_type_and_tracker : client_tracker_map_) {
-    std::set<url::Origin> client_origins =
-        client_type_and_tracker.second->GetCachedOrigins();
-    for (const auto& client_origin : client_origins)
-      origins.insert(client_origin);
+  for (const auto& client_type_and_trackers : client_tracker_map_) {
+    for (const auto& client_tracker : client_type_and_trackers.second) {
+      std::set<url::Origin> client_origins = client_tracker->GetCachedOrigins();
+      for (const auto& client_origin : client_origins)
+        origins.insert(client_origin);
+    }
   }
   return origins;
 }
@@ -210,9 +231,8 @@
                                         bool enabled) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(client_tracker_map_.count(client_type));
-  ClientUsageTracker* client_tracker = client_tracker_map_[client_type].get();
-
-  client_tracker->SetUsageCacheEnabled(origin, enabled);
+  for (const auto& client_tracker : client_tracker_map_[client_type])
+    client_tracker->SetUsageCacheEnabled(origin, enabled);
 }
 
 void UsageTracker::AccumulateClientGlobalLimitedUsage(AccumulateInfo* info,
diff --git a/storage/browser/quota/usage_tracker.h b/storage/browser/quota/usage_tracker.h
index dc5446f9..aae1383 100644
--- a/storage/browser/quota/usage_tracker.h
+++ b/storage/browser/quota/usage_tracker.h
@@ -15,10 +15,12 @@
 
 #include "base/callback.h"
 #include "base/component_export.h"
+#include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "base/sequence_checker.h"
 #include "storage/browser/quota/quota_callbacks.h"
 #include "storage/browser/quota/quota_client.h"
+#include "storage/browser/quota/quota_client_type.h"
 #include "storage/browser/quota/quota_task.h"
 #include "storage/browser/quota/special_storage_policy.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
@@ -38,9 +40,10 @@
 class COMPONENT_EXPORT(STORAGE_BROWSER) UsageTracker
     : public QuotaTaskObserver {
  public:
-  UsageTracker(const std::vector<scoped_refptr<QuotaClient>>& clients,
-               blink::mojom::StorageType type,
-               SpecialStoragePolicy* special_storage_policy);
+  UsageTracker(
+      const base::flat_map<QuotaClient*, QuotaClientType>& client_types,
+      blink::mojom::StorageType type,
+      SpecialStoragePolicy* special_storage_policy);
   ~UsageTracker() override;
 
   blink::mojom::StorageType type() const {
@@ -87,8 +90,10 @@
                                          const std::string& host);
 
   const blink::mojom::StorageType type_;
-  std::map<QuotaClientType, std::unique_ptr<ClientUsageTracker>>
+  base::flat_map<QuotaClientType,
+                 std::vector<std::unique_ptr<ClientUsageTracker>>>
       client_tracker_map_;
+  size_t client_count_;
 
   std::vector<UsageCallback> global_limited_usage_callbacks_;
   std::vector<GlobalUsageCallback> global_usage_callbacks_;
diff --git a/storage/browser/quota/usage_tracker_unittest.cc b/storage/browser/quota/usage_tracker_unittest.cc
index 1b07b48..127fc7d7 100644
--- a/storage/browser/quota/usage_tracker_unittest.cc
+++ b/storage/browser/quota/usage_tracker_unittest.cc
@@ -48,8 +48,6 @@
  public:
   UsageTrackerTestQuotaClient() = default;
 
-  QuotaClientType type() const override { return QuotaClientType::kFileSystem; }
-
   void OnQuotaManagerDestroyed() override {}
 
   void GetOriginUsage(const url::Origin& origin,
@@ -132,7 +130,7 @@
   UsageTrackerTest()
       : storage_policy_(new MockSpecialStoragePolicy()),
         quota_client_(base::MakeRefCounted<UsageTrackerTestQuotaClient>()),
-        usage_tracker_(GetUsageTrackerList(),
+        usage_tracker_(GetQuotaClientMap(),
                        StorageType::kTemporary,
                        storage_policy_.get()) {}
 
@@ -156,7 +154,8 @@
 
   void UpdateUsage(const url::Origin& origin, int64_t delta) {
     quota_client_->UpdateUsage(origin, delta);
-    usage_tracker_.UpdateUsageCache(quota_client_->type(), origin, delta);
+    usage_tracker_.UpdateUsageCache(QuotaClientType::kFileSystem, origin,
+                                    delta);
     base::RunLoop().RunUntilIdle();
   }
 
@@ -223,14 +222,16 @@
   }
 
   void SetUsageCacheEnabled(const url::Origin& origin, bool enabled) {
-    usage_tracker_.SetUsageCacheEnabled(quota_client_->type(), origin, enabled);
+    usage_tracker_.SetUsageCacheEnabled(QuotaClientType::kFileSystem, origin,
+                                        enabled);
   }
 
  private:
-  std::vector<scoped_refptr<QuotaClient>> GetUsageTrackerList() {
-    std::vector<scoped_refptr<QuotaClient>> client_list;
-    client_list.push_back(quota_client_);
-    return client_list;
+  base::flat_map<QuotaClient*, QuotaClientType> GetQuotaClientMap() {
+    base::flat_map<QuotaClient*, QuotaClientType> client_map;
+    client_map.insert(
+        std::make_pair(quota_client_.get(), QuotaClientType::kFileSystem));
+    return client_map;
   }
 
   base::test::TaskEnvironment task_environment_;
diff --git a/storage/browser/test/mock_quota_client.cc b/storage/browser/test/mock_quota_client.cc
index b752f5e..bbb3600 100644
--- a/storage/browser/test/mock_quota_client.cc
+++ b/storage/browser/test/mock_quota_client.cc
@@ -14,6 +14,7 @@
 #include "base/stl_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "net/base/url_util.h"
+#include "storage/browser/quota/quota_client_type.h"
 #include "storage/browser/quota/quota_manager_proxy.h"
 #include "url/gurl.h"
 
@@ -42,7 +43,7 @@
   DCHECK_GE(size, 0);
   origin_data_[{origin, storage_type}] = size;
   quota_manager_proxy_->quota_manager()->NotifyStorageModifiedInternal(
-      type(), origin, storage_type, size, IncrementMockTime());
+      client_type_, origin, storage_type, size, IncrementMockTime());
 }
 
 void MockQuotaClient::ModifyOriginAndNotify(
@@ -56,13 +57,13 @@
 
   // TODO(tzik): Check quota to prevent usage exceed
   quota_manager_proxy_->quota_manager()->NotifyStorageModifiedInternal(
-      type(), origin, storage_type, delta, IncrementMockTime());
+      client_type_, origin, storage_type, delta, IncrementMockTime());
 }
 
 void MockQuotaClient::TouchAllOriginsAndNotify() {
   for (const auto& origin_type : origin_data_) {
     quota_manager_proxy_->quota_manager()->NotifyStorageModifiedInternal(
-        type(), origin_type.first.first, origin_type.first.second, 0,
+        client_type_, origin_type.first.first, origin_type.first.second, 0,
         IncrementMockTime());
   }
 }
@@ -77,10 +78,6 @@
   return base::Time::FromDoubleT(mock_time_counter_ * 10.0);
 }
 
-QuotaClientType MockQuotaClient::type() const {
-  return client_type_;
-}
-
 void MockQuotaClient::OnQuotaManagerDestroyed() {}
 
 void MockQuotaClient::GetOriginUsage(const url::Origin& origin,
@@ -175,8 +172,8 @@
   auto it = origin_data_.find(std::make_pair(origin, storage_type));
   if (it != origin_data_.end()) {
     int64_t delta = it->second;
-    quota_manager_proxy_->NotifyStorageModified(type(), origin, storage_type,
-                                                -delta);
+    quota_manager_proxy_->NotifyStorageModified(client_type_, origin,
+                                                storage_type, -delta);
     origin_data_.erase(it);
   }
 
diff --git a/storage/browser/test/mock_quota_client.h b/storage/browser/test/mock_quota_client.h
index 295841d..533c7430 100644
--- a/storage/browser/test/mock_quota_client.h
+++ b/storage/browser/test/mock_quota_client.h
@@ -56,7 +56,6 @@
   base::Time IncrementMockTime();
 
   // QuotaClient.
-  QuotaClientType type() const override;
   void OnQuotaManagerDestroyed() override;
   void GetOriginUsage(const url::Origin& origin,
                       blink::mojom::StorageType type,
diff --git a/storage/browser/test/mock_quota_manager_proxy.cc b/storage/browser/test/mock_quota_manager_proxy.cc
index b858444..fcd122c1 100644
--- a/storage/browser/test/mock_quota_manager_proxy.cc
+++ b/storage/browser/test/mock_quota_manager_proxy.cc
@@ -20,7 +20,8 @@
       last_notified_delta_(0),
       registered_client_(nullptr) {}
 
-void MockQuotaManagerProxy::RegisterClient(scoped_refptr<QuotaClient> client) {
+void MockQuotaManagerProxy::RegisterClient(scoped_refptr<QuotaClient> client,
+                                           QuotaClientType client_type) {
   DCHECK(!registered_client_);
   registered_client_ = std::move(client);
 }
diff --git a/storage/browser/test/mock_quota_manager_proxy.h b/storage/browser/test/mock_quota_manager_proxy.h
index 5ec3c19..334694f8 100644
--- a/storage/browser/test/mock_quota_manager_proxy.h
+++ b/storage/browser/test/mock_quota_manager_proxy.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "storage/browser/quota/quota_client.h"
+#include "storage/browser/quota/quota_client_type.h"
 #include "storage/browser/quota/quota_manager_proxy.h"
 #include "storage/browser/test/mock_quota_manager.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
@@ -17,6 +18,7 @@
 namespace storage {
 
 class MockQuotaManager;
+enum class QuotaClientType;
 
 class MockQuotaManagerProxy : public QuotaManagerProxy {
  public:
@@ -24,7 +26,8 @@
   MockQuotaManagerProxy(MockQuotaManager* quota_manager,
                         base::SingleThreadTaskRunner* task_runner);
 
-  void RegisterClient(scoped_refptr<QuotaClient> client) override;
+  void RegisterClient(scoped_refptr<QuotaClient> client,
+                      QuotaClientType client_type) override;
 
   virtual void SimulateQuotaManagerDestroyed();
 
diff --git a/testing/merge_scripts/code_coverage/merge_lib.py b/testing/merge_scripts/code_coverage/merge_lib.py
index 9285112..c219959a 100644
--- a/testing/merge_scripts/code_coverage/merge_lib.py
+++ b/testing/merge_scripts/code_coverage/merge_lib.py
@@ -252,7 +252,8 @@
                    input_extension,
                    profdata_tool_path,
                    input_filename_pattern='.*',
-                   sparse=True):
+                   sparse=True,
+                   skip_validation=False):
   """Merges the profiles produced by the shards using llvm-profdata.
 
   Args:
@@ -265,6 +266,8 @@
         a valid regex pattern if present.
     sparse (bool): flag to indicate whether to run llvm-profdata with --sparse.
       Doc: https://llvm.org/docs/CommandGuide/llvm-profdata.html#profdata-merge
+    skip_validation (bool): flag to skip the _validate_and_convert_profraws
+        invocation. only applicable when input_extension is .profraw.
 
   Returns:
     The list of profiles that had to be excluded to get the merge to
@@ -275,7 +278,12 @@
                                                 input_filename_pattern)
   invalid_profraw_files = []
   counter_overflows = []
-  if input_extension == '.profraw':
+
+  if skip_validation:
+    logging.warning('--skip-validation has been enabled. Skipping conversion '
+                    'to ensure that profiles are valid.')
+
+  if input_extension == '.profraw' and not skip_validation:
     profile_input_file_paths, invalid_profraw_files, counter_overflows = (
         _validate_and_convert_profraws(profile_input_file_paths,
                                        profdata_tool_path,
diff --git a/testing/merge_scripts/code_coverage/merge_results.py b/testing/merge_scripts/code_coverage/merge_results.py
index d8ea2e0..199464b 100755
--- a/testing/merge_scripts/code_coverage/merge_results.py
+++ b/testing/merge_scripts/code_coverage/merge_results.py
@@ -72,6 +72,15 @@
       action='store_true',
       dest='sparse',
       help='run llvm-profdata with the sparse flag.')
+  # (crbug.com/1091310) - IR PGO is incompatible with the initial conversion
+  # of .profraw -> .profdata that's run to detect validation errors.
+  # Introducing a bypass flag that'll merge all .profraw directly to .profdata
+  parser.add_argument(
+      '--skip-validation',
+      action='store_true',
+      help='skip validation for good raw profile data. this will pass all '
+           'raw profiles found to llvm-profdata to be merged. only applicable '
+           'when input extension is .profraw.')
   return parser
 
 
@@ -106,7 +115,8 @@
       params.task_output_dir,
       os.path.join(params.profdata_dir, output_prodata_filename), '.profraw',
       params.llvm_profdata,
-      sparse=params.sparse)
+      sparse=params.sparse,
+      skip_validation=params.skip_validation)
 
   # At the moment counter overflows overlap with invalid profiles, but this is
   # not guaranteed to remain the case indefinitely. To avoid future conflicts
diff --git a/testing/merge_scripts/code_coverage/merge_results_test.py b/testing/merge_scripts/code_coverage/merge_results_test.py
index 2af89a62..d490b74b 100755
--- a/testing/merge_scripts/code_coverage/merge_results_test.py
+++ b/testing/merge_scripts/code_coverage/merge_results_test.py
@@ -55,7 +55,8 @@
         self.assertEqual(
             mock_merge.call_args,
             mock.call(task_output_dir, profdata_file, '.profraw',
-                      'llvm-profdata', sparse=True), None)
+                      'llvm-profdata', sparse=True,
+                      skip_validation=False), None)
 
   def test_merge_steps_parameters(self):
     """Test the build-level merge front-end."""
@@ -123,6 +124,45 @@
 
     self.assertTrue(mock_validate_and_convert_profraws.called)
 
+  @mock.patch.object(merger, '_validate_and_convert_profraws')
+  def test_profraw_skip_validation(self, mock_validate_and_convert_profraws):
+    mock_input_dir_walk = [
+        ('/b/some/path', ['0', '1', '2', '3'], ['summary.json']),
+        ('/b/some/path/0', [],
+         ['output.json', 'default-1.profraw', 'default-2.profraw']),
+        ('/b/some/path/1', [],
+         ['output.json', 'default-1.profraw', 'default-2.profraw']),
+    ]
+
+    with mock.patch.object(os, 'walk') as mock_walk:
+      with mock.patch.object(os, 'remove'):
+        mock_walk.return_value = mock_input_dir_walk
+        with mock.patch.object(subprocess, 'check_output') as mock_exec_cmd:
+          merger.merge_profiles('/b/some/path',
+                                'output/dir/default.profdata',
+                                '.profraw',
+                                'llvm-profdata',
+                                skip_validation=True)
+          self.assertEqual(
+              mock.call(
+                  [
+                      'llvm-profdata',
+                      'merge',
+                      '-o',
+                      'output/dir/default.profdata',
+                      '-sparse=true',
+                      '/b/some/path/0/default-1.profraw',
+                      '/b/some/path/0/default-2.profraw',
+                      '/b/some/path/1/default-1.profraw',
+                      '/b/some/path/1/default-2.profraw'
+                  ],
+                  stderr=-2,
+              ), mock_exec_cmd.call_args)
+
+    # Skip validation should've passed all profraw files directly, and
+    # this validate call should not have been invoked.
+    self.assertFalse(mock_validate_and_convert_profraws.called)
+
 
   def test_merge_profraw_skip_if_there_is_no_file(self):
     mock_input_dir_walk = [
@@ -380,7 +420,8 @@
           self.assertEqual(
               mock_merge.call_args,
               mock.call(task_output_dir, profdata_file, '.profraw',
-                        'llvm-profdata', sparse=expected_outcome), None)
+                        'llvm-profdata', sparse=expected_outcome,
+                        skip_validation=False), None)
 
 
 if __name__ == '__main__':
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 884a277..df9775b 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -591,11 +591,12 @@
             ]
         }
     ],
-    "AutofillCacheServerCardInfoLaunch": [
+    "AutofillCacheServerCardInfo": [
         {
             "platforms": [
                 "android",
                 "android_weblayer",
+                "android_webview",
                 "chromeos",
                 "ios",
                 "linux",
diff --git a/third_party/abseil-cpp/BUILD.bazel b/third_party/abseil-cpp/BUILD.bazel
new file mode 100644
index 0000000..79fb0ecd7
--- /dev/null
+++ b/third_party/abseil-cpp/BUILD.bazel
@@ -0,0 +1,25 @@
+#
+# Copyright 2020 The Abseil Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache 2.0
+
+# Expose license for external usage through bazel.
+exports_files([
+    "AUTHORS",
+    "LICENSE",
+])
diff --git a/third_party/abseil-cpp/CMake/AbseilDll.cmake b/third_party/abseil-cpp/CMake/AbseilDll.cmake
index ccd409f..8e93e794 100644
--- a/third_party/abseil-cpp/CMake/AbseilDll.cmake
+++ b/third_party/abseil-cpp/CMake/AbseilDll.cmake
@@ -15,6 +15,7 @@
   "base/internal/cycleclock.cc"
   "base/internal/cycleclock.h"
   "base/internal/direct_mmap.h"
+  "base/internal/dynamic_annotations.h"
   "base/internal/endian.h"
   "base/internal/errno_saver.h"
   "base/internal/exponential_biased.cc"
diff --git a/third_party/abseil-cpp/CMakeLists.txt b/third_party/abseil-cpp/CMakeLists.txt
index 4767045..4d10710e 100644
--- a/third_party/abseil-cpp/CMakeLists.txt
+++ b/third_party/abseil-cpp/CMakeLists.txt
@@ -99,10 +99,8 @@
   # on the command line
   include(CTest)
   enable_testing()
-endif()
 
-## check targets
-if(BUILD_TESTING)
+  ## check targets
   if (NOT ABSL_USE_EXTERNAL_GOOGLETEST)
     set(absl_gtest_build_dir ${CMAKE_BINARY_DIR}/googletest-build)
     if(${ABSL_USE_GOOGLETEST_HEAD})
@@ -174,5 +172,7 @@
     FILES_MATCHING
       PATTERN "*.inc"
       PATTERN "*.h"
-  )
+      PATTERN "copts" EXCLUDE
+      PATTERN "testdata" EXCLUDE
+    )
 endif()  # ABSL_ENABLE_INSTALL
diff --git a/third_party/abseil-cpp/README.chromium b/third_party/abseil-cpp/README.chromium
index c1d332e..bd1485c 100644
--- a/third_party/abseil-cpp/README.chromium
+++ b/third_party/abseil-cpp/README.chromium
@@ -4,7 +4,7 @@
 License: Apache 2.0
 License File: LICENSE
 Version: 0
-Revision: 33caf1097ecce4fe892567462fa8821d477854b4
+Revision: da3a87690c56f965705b6a233d25ba5a3294067c
 Security Critical: yes
 
 Description:
diff --git a/third_party/abseil-cpp/WORKSPACE b/third_party/abseil-cpp/WORKSPACE
index f2b1046..1a1da6c 100644
--- a/third_party/abseil-cpp/WORKSPACE
+++ b/third_party/abseil-cpp/WORKSPACE
@@ -19,10 +19,10 @@
 
 # GoogleTest/GoogleMock framework. Used by most unit-tests.
 http_archive(
-     name = "com_google_googletest",
-     urls = ["https://github.com/google/googletest/archive/b6cd405286ed8635ece71c72f118e659f4ade3fb.zip"],  # 2019-01-07
-     strip_prefix = "googletest-b6cd405286ed8635ece71c72f118e659f4ade3fb",
-     sha256 = "ff7a82736e158c077e76188232eac77913a15dac0b22508c390ab3f88e6d6d86",
+    name = "com_google_googletest",
+    urls = ["https://github.com/google/googletest/archive/011959aafddcd30611003de96cfd8d7a7685c700.zip"],  # 2020-05-14T00:36:05Z
+    strip_prefix = "googletest-011959aafddcd30611003de96cfd8d7a7685c700",
+    sha256 = "6a5d7d63cd6e0ad2a7130471105a3b83799a7a2b14ef7ec8d742b54f01a4833c",
 )
 
 # Google benchmark.
diff --git a/third_party/abseil-cpp/absl/algorithm/container.h b/third_party/abseil-cpp/absl/algorithm/container.h
index d72532d..2457d78b 100644
--- a/third_party/abseil-cpp/absl/algorithm/container.h
+++ b/third_party/abseil-cpp/absl/algorithm/container.h
@@ -943,9 +943,10 @@
 // c_partial_sort_copy()
 //
 // Container-based version of the <algorithm> `std::partial_sort_copy()`
-// function to sort elements within a container such that elements before
-// `middle` are sorted in ascending order, and return the result within an
-// iterator.
+// function to sort the elements in the given range `result` within the larger
+// `sequence` in ascending order (and using `result` as the output parameter).
+// At most min(result.last - result.first, sequence.last - sequence.first)
+// elements from the sequence will be stored in the result.
 template <typename C, typename RandomAccessContainer>
 container_algorithm_internal::ContainerIter<RandomAccessContainer>
 c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) {
diff --git a/third_party/abseil-cpp/absl/base/BUILD.bazel b/third_party/abseil-cpp/absl/base/BUILD.bazel
index 76122dab..35cb2e9 100644
--- a/third_party/abseil-cpp/absl/base/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/base/BUILD.bazel
@@ -115,10 +115,18 @@
 
 cc_library(
     name = "dynamic_annotations",
-    srcs = ["dynamic_annotations.cc"],
-    hdrs = ["dynamic_annotations.h"],
+    srcs = [
+        "dynamic_annotations.cc",
+        "internal/dynamic_annotations.h",
+    ],
+    hdrs = [
+        "dynamic_annotations.h",
+    ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":config",
+    ],
 )
 
 cc_library(
diff --git a/third_party/abseil-cpp/absl/base/BUILD.gn b/third_party/abseil-cpp/absl/base/BUILD.gn
index 2ed5456..8b19d23f 100644
--- a/third_party/abseil-cpp/absl/base/BUILD.gn
+++ b/third_party/abseil-cpp/absl/base/BUILD.gn
@@ -77,6 +77,7 @@
   # their usage is deprecated in Chromium (see README.chromium for more info).
   visibility = []
   visibility = [ "//third_party/abseil-cpp/absl/*" ]
+  deps = [ ":config" ]
 }
 
 absl_source_set("core_headers") {
diff --git a/third_party/abseil-cpp/absl/base/CMakeLists.txt b/third_party/abseil-cpp/absl/base/CMakeLists.txt
index 292998b3..b7c01c9 100644
--- a/third_party/abseil-cpp/absl/base/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/base/CMakeLists.txt
@@ -106,8 +106,11 @@
     "dynamic_annotations.h"
   SRCS
     "dynamic_annotations.cc"
+    "internal/dynamic_annotations.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::config
   PUBLIC
 )
 
diff --git a/third_party/abseil-cpp/absl/base/dynamic_annotations.cc b/third_party/abseil-cpp/absl/base/dynamic_annotations.cc
index 1411093..e40e2173 100644
--- a/third_party/abseil-cpp/absl/base/dynamic_annotations.cc
+++ b/third_party/abseil-cpp/absl/base/dynamic_annotations.cc
@@ -17,72 +17,17 @@
 
 #include "absl/base/dynamic_annotations.h"
 
-#ifndef __has_feature
-#define __has_feature(x) 0
-#endif
-
-/* Compiler-based ThreadSanitizer defines
-   ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1
-   and provides its own definitions of the functions. */
+// Compiler-based ThreadSanitizer defines
+// ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1
+// and provides its own definitions of the functions.
 
 #ifndef ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL
 # define ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL 0
 #endif
 
-/* Each function is empty and called (via a macro) only in debug mode.
-   The arguments are captured by dynamic tools at runtime. */
-
 #if ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 && !defined(__native_client__)
 
-#if __has_feature(memory_sanitizer)
-#include <sanitizer/msan_interface.h>
-#endif
-
-#ifdef __cplusplus
 extern "C" {
-#endif
-
-void AbslAnnotateRWLockCreate(const char *, int,
-                          const volatile void *){}
-void AbslAnnotateRWLockDestroy(const char *, int,
-                           const volatile void *){}
-void AbslAnnotateRWLockAcquired(const char *, int,
-                            const volatile void *, long){}
-void AbslAnnotateRWLockReleased(const char *, int,
-                            const volatile void *, long){}
-void AbslAnnotateBenignRace(const char *, int,
-                        const volatile void *,
-                        const char *){}
-void AbslAnnotateBenignRaceSized(const char *, int,
-                             const volatile void *,
-                             size_t,
-                             const char *) {}
-void AbslAnnotateThreadName(const char *, int,
-                        const char *){}
-void AbslAnnotateIgnoreReadsBegin(const char *, int){}
-void AbslAnnotateIgnoreReadsEnd(const char *, int){}
-void AbslAnnotateIgnoreWritesBegin(const char *, int){}
-void AbslAnnotateIgnoreWritesEnd(const char *, int){}
-void AbslAnnotateEnableRaceDetection(const char *, int, int){}
-void AbslAnnotateMemoryIsInitialized(const char *, int,
-                                 const volatile void *mem, size_t size) {
-#if __has_feature(memory_sanitizer)
-  __msan_unpoison(mem, size);
-#else
-  (void)mem;
-  (void)size;
-#endif
-}
-
-void AbslAnnotateMemoryIsUninitialized(const char *, int,
-                                   const volatile void *mem, size_t size) {
-#if __has_feature(memory_sanitizer)
-  __msan_allocated_memory(mem, size);
-#else
-  (void)mem;
-  (void)size;
-#endif
-}
 
 static int AbslGetRunningOnValgrind(void) {
 #ifdef RUNNING_ON_VALGRIND
@@ -95,21 +40,21 @@
   return 0;
 }
 
-/* See the comments in dynamic_annotations.h */
+// See the comments in dynamic_annotations.h
 int AbslRunningOnValgrind(void) {
   static volatile int running_on_valgrind = -1;
   int local_running_on_valgrind = running_on_valgrind;
-  /* C doesn't have thread-safe initialization of statics, and we
-     don't want to depend on pthread_once here, so hack it. */
+  // C doesn't have thread-safe initialization of statics, and we
+  // don't want to depend on pthread_once here, so hack it.
   ABSL_ANNOTATE_BENIGN_RACE(&running_on_valgrind, "safe hack");
   if (local_running_on_valgrind == -1)
     running_on_valgrind = local_running_on_valgrind = AbslGetRunningOnValgrind();
   return local_running_on_valgrind;
 }
 
-/* See the comments in dynamic_annotations.h */
+// See the comments in dynamic_annotations.h
 double AbslValgrindSlowdown(void) {
-  /* Same initialization hack as in AbslRunningOnValgrind(). */
+  // Same initialization hack as in AbslRunningOnValgrind().
   static volatile double slowdown = 0.0;
   double local_slowdown = slowdown;
   ABSL_ANNOTATE_BENIGN_RACE(&slowdown, "safe hack");
@@ -123,7 +68,5 @@
   return local_slowdown;
 }
 
-#ifdef __cplusplus
 }  // extern "C"
-#endif
-#endif  /* ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */
+#endif  // ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0
diff --git a/third_party/abseil-cpp/absl/base/dynamic_annotations.h b/third_party/abseil-cpp/absl/base/dynamic_annotations.h
index 0ac32f3..1a50ba81 100644
--- a/third_party/abseil-cpp/absl/base/dynamic_annotations.h
+++ b/third_party/abseil-cpp/absl/base/dynamic_annotations.h
@@ -1,386 +1,501 @@
-/*
- *  Copyright 2017 The Abseil Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/* This file defines dynamic annotations for use with dynamic analysis
-   tool such as valgrind, PIN, etc.
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 
-   Dynamic annotation is a source code annotation that affects
-   the generated code (that is, the annotation is not a comment).
-   Each such annotation is attached to a particular
-   instruction and/or to a particular object (address) in the program.
-
-   The annotations that should be used by users are macros in all upper-case
-   (e.g., ABSL_ANNOTATE_THREAD_NAME).
-
-   Actual implementation of these macros may differ depending on the
-   dynamic analysis tool being used.
-
-   This file supports the following configurations:
-   - Dynamic Annotations enabled (with static thread-safety warnings disabled).
-     In this case, macros expand to functions implemented by Thread Sanitizer,
-     when building with TSan. When not provided an external implementation,
-     dynamic_annotations.cc provides no-op implementations.
-
-   - Static Clang thread-safety warnings enabled.
-     When building with a Clang compiler that supports thread-safety warnings,
-     a subset of annotations can be statically-checked at compile-time. We
-     expand these macros to static-inline functions that can be analyzed for
-     thread-safety, but afterwards elided when building the final binary.
-
-   - All annotations are disabled.
-     If neither Dynamic Annotations nor Clang thread-safety warnings are
-     enabled, then all annotation-macros expand to empty. */
+// This file defines dynamic annotations for use with dynamic analysis tool
+// such as valgrind, PIN, etc.
+//
+// Dynamic annotation is a source code annotation that affects the generated
+// code (that is, the annotation is not a comment). Each such annotation is
+// attached to a particular instruction and/or to a particular object (address)
+// in the program.
+//
+// The annotations that should be used by users are macros in all upper-case
+// (e.g., ABSL_ANNOTATE_THREAD_NAME).
+//
+// Actual implementation of these macros may differ depending on the dynamic
+// analysis tool being used.
+//
+// This file supports the following configurations:
+// - Dynamic Annotations enabled (with static thread-safety warnings disabled).
+//   In this case, macros expand to functions implemented by Thread Sanitizer,
+//   when building with TSan. When not provided an external implementation,
+//   dynamic_annotations.cc provides no-op implementations.
+//
+// - Static Clang thread-safety warnings enabled.
+//   When building with a Clang compiler that supports thread-safety warnings,
+//   a subset of annotations can be statically-checked at compile-time. We
+//   expand these macros to static-inline functions that can be analyzed for
+//   thread-safety, but afterwards elided when building the final binary.
+//
+// - All annotations are disabled.
+//   If neither Dynamic Annotations nor Clang thread-safety warnings are
+//   enabled, then all annotation-macros expand to empty.
 
 #ifndef ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
 #define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
 
+#include <stddef.h>
+
+#include "absl/base/config.h"
+
+// -------------------------------------------------------------------------
+// Decide which features are enabled
+
 #ifndef ABSL_DYNAMIC_ANNOTATIONS_ENABLED
-# define ABSL_DYNAMIC_ANNOTATIONS_ENABLED 0
+#define ABSL_DYNAMIC_ANNOTATIONS_ENABLED 0
+#endif
+
+#if defined(__clang__) && !defined(SWIG)
+#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1
+#else
+#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 0
 #endif
 
 #if ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0
 
-  /* -------------------------------------------------------------
-     Annotations that suppress errors.  It is usually better to express the
-     program's synchronization using the other annotations, but these can
-     be used when all else fails. */
+#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
+#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1
 
-  /* Report that we may have a benign race at "pointer", with size
-     "sizeof(*(pointer))". "pointer" must be a non-void* pointer.  Insert at the
-     point where "pointer" has been allocated, preferably close to the point
-     where the race happens.  See also ABSL_ANNOTATE_BENIGN_RACE_STATIC. */
-  #define ABSL_ANNOTATE_BENIGN_RACE(pointer, description) \
-    AbslAnnotateBenignRaceSized(__FILE__, __LINE__, pointer, \
-                            sizeof(*(pointer)), description)
+#else
 
-  /* Same as ABSL_ANNOTATE_BENIGN_RACE(address, description), but applies to
-     the memory range [address, address+size). */
-  #define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
-    AbslAnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description)
+#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0
+#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0
+#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0
 
-  /* Enable (enable!=0) or disable (enable==0) race detection for all threads.
-     This annotation could be useful if you want to skip expensive race analysis
-     during some period of program execution, e.g. during initialization. */
-  #define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) \
-    AbslAnnotateEnableRaceDetection(__FILE__, __LINE__, enable)
+// Clang provides limited support for static thread-safety analysis through a
+// feature called Annotalysis. We configure macro-definitions according to
+// whether Annotalysis support is available. When running in opt-mode, GCC
+// will issue a warning, if these attributes are compiled. Only include them
+// when compiling using Clang.
 
-  /* -------------------------------------------------------------
-     Annotations useful for debugging. */
+// ABSL_ANNOTALYSIS_ENABLED == 1 when IGNORE_READ_ATTRIBUTE_ENABLED == 1
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED \
+  ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED
+// Read/write annotations are enabled in Annotalysis mode; disabled otherwise.
+#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \
+  ABSL_INTERNAL_ANNOTALYSIS_ENABLED
+#endif
 
-  /* Report the current thread name to a race detector. */
-  #define ABSL_ANNOTATE_THREAD_NAME(name) \
-    AbslAnnotateThreadName(__FILE__, __LINE__, name)
+// Memory annotations are also made available to LLVM's Memory Sanitizer
+#if defined(MEMORY_SANITIZER) && defined(__has_feature) && \
+    !defined(__native_client__)
+#if __has_feature(memory_sanitizer)
+#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 1
+#endif
+#endif
 
-  /* -------------------------------------------------------------
-     Annotations useful when implementing locks.  They are not
-     normally needed by modules that merely use locks.
-     The "lock" argument is a pointer to the lock object. */
+#ifndef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
+#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 0
+#endif
 
-  /* Report that a lock has been created at address "lock". */
-  #define ABSL_ANNOTATE_RWLOCK_CREATE(lock) \
-    AbslAnnotateRWLockCreate(__FILE__, __LINE__, lock)
+#ifdef __cplusplus
+#define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" {
+#define ABSL_INTERNAL_END_EXTERN_C }  // extern "C"
+#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F
+#define ABSL_INTERNAL_STATIC_INLINE inline
+#else
+#define ABSL_INTERNAL_BEGIN_EXTERN_C  // empty
+#define ABSL_INTERNAL_END_EXTERN_C    // empty
+#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F
+#define ABSL_INTERNAL_STATIC_INLINE static inline
+#endif
 
-  /* Report that a linker initialized lock has been created at address "lock".
-   */
+// -------------------------------------------------------------------------
+// Define race annotations.
+
+#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1
+
+// -------------------------------------------------------------
+// Annotations that suppress errors. It is usually better to express the
+// program's synchronization using the other annotations, but these can be used
+// when all else fails.
+
+// Report that we may have a benign race at `pointer`, with size
+// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the
+// point where `pointer` has been allocated, preferably close to the point
+// where the race happens. See also ABSL_ANNOTATE_BENIGN_RACE_STATIC.
+#define ABSL_ANNOTATE_BENIGN_RACE(pointer, description) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslAnnotateBenignRaceSized)  \
+  (__FILE__, __LINE__, pointer, sizeof(*(pointer)), description)
+
+// Same as ABSL_ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to
+// the memory range [`address`, `address`+`size`).
+#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslAnnotateBenignRaceSized)              \
+  (__FILE__, __LINE__, address, size, description)
+
+// Enable (`enable`!=0) or disable (`enable`==0) race detection for all threads.
+// This annotation could be useful if you want to skip expensive race analysis
+// during some period of program execution, e.g. during initialization.
+#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable)        \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslAnnotateEnableRaceDetection) \
+  (__FILE__, __LINE__, enable)
+
+// -------------------------------------------------------------
+// Annotations useful for debugging.
+
+// Report the current thread `name` to a race detector.
+#define ABSL_ANNOTATE_THREAD_NAME(name) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslAnnotateThreadName)(__FILE__, __LINE__, name)
+
+// -------------------------------------------------------------
+// Annotations useful when implementing locks. They are not normally needed by
+// modules that merely use locks. The `lock` argument is a pointer to the lock
+// object.
+
+// Report that a lock has been created at address `lock`.
+#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslAnnotateRWLockCreate)(__FILE__, __LINE__, lock)
+
+// Report that a linker initialized lock has been created at address `lock`.
 #ifdef THREAD_SANITIZER
-  #define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
-    AbslAnnotateRWLockCreateStatic(__FILE__, __LINE__, lock)
+#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock)          \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslAnnotateRWLockCreateStatic) \
+  (__FILE__, __LINE__, lock)
 #else
-  #define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) ABSL_ANNOTATE_RWLOCK_CREATE(lock)
+#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
+  ABSL_ANNOTATE_RWLOCK_CREATE(lock)
 #endif
 
-  /* Report that the lock at address "lock" is about to be destroyed. */
-  #define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) \
-    AbslAnnotateRWLockDestroy(__FILE__, __LINE__, lock)
+// Report that the lock at address `lock` is about to be destroyed.
+#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslAnnotateRWLockDestroy)(__FILE__, __LINE__, lock)
 
-  /* Report that the lock at address "lock" has been acquired.
-     is_w=1 for writer lock, is_w=0 for reader lock. */
-  #define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
-    AbslAnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w)
+// Report that the lock at address `lock` has been acquired.
+// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
+#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w)     \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslAnnotateRWLockAcquired) \
+  (__FILE__, __LINE__, lock, is_w)
 
-  /* Report that the lock at address "lock" is about to be released. */
-  #define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
-    AbslAnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w)
+// Report that the lock at address `lock` is about to be released.
+// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
+#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w)     \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslAnnotateRWLockReleased) \
+  (__FILE__, __LINE__, lock, is_w)
 
-#else  /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0 */
+// Apply ABSL_ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`.
+#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description)      \
+  namespace {                                                          \
+  class static_var##_annotator {                                       \
+   public:                                                             \
+    static_var##_annotator() {                                         \
+      ABSL_ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), \
+                                      #static_var ": " description);   \
+    }                                                                  \
+  };                                                                   \
+  static static_var##_annotator the##static_var##_annotator;           \
+  }  // namespace
 
-  #define ABSL_ANNOTATE_RWLOCK_CREATE(lock) /* empty */
-  #define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) /* empty */
-  #define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) /* empty */
-  #define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */
-  #define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */
-  #define ABSL_ANNOTATE_BENIGN_RACE(address, description) /* empty */
-  #define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */
-  #define ABSL_ANNOTATE_THREAD_NAME(name) /* empty */
-  #define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */
+// Function prototypes of annotations provided by the compiler-based sanitizer
+// implementation.
+ABSL_INTERNAL_BEGIN_EXTERN_C
+void AbslAnnotateRWLockCreate(const char* file, int line,
+                          const volatile void* lock);
+void AbslAnnotateRWLockCreateStatic(const char* file, int line,
+                                const volatile void* lock);
+void AbslAnnotateRWLockDestroy(const char* file, int line,
+                           const volatile void* lock);
+void AbslAnnotateRWLockAcquired(const char* file, int line,
+                            const volatile void* lock, long is_w);  // NOLINT
+void AbslAnnotateRWLockReleased(const char* file, int line,
+                            const volatile void* lock, long is_w);  // NOLINT
+void AbslAnnotateBenignRace(const char* file, int line,
+                        const volatile void* address, const char* description);
+void AbslAnnotateBenignRaceSized(const char* file, int line,
+                             const volatile void* address, size_t size,
+                             const char* description);
+void AbslAnnotateThreadName(const char* file, int line, const char* name);
+void AbslAnnotateEnableRaceDetection(const char* file, int line, int enable);
+ABSL_INTERNAL_END_EXTERN_C
 
-#endif  /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED */
+#else  // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0
 
-/* These annotations are also made available to LLVM's Memory Sanitizer */
-#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 1 || defined(MEMORY_SANITIZER)
-  #define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
-    AbslAnnotateMemoryIsInitialized(__FILE__, __LINE__, address, size)
+#define ABSL_ANNOTATE_RWLOCK_CREATE(lock)                            // empty
+#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock)                     // empty
+#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock)                           // empty
+#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w)                    // empty
+#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w)                    // empty
+#define ABSL_ANNOTATE_BENIGN_RACE(address, description)              // empty
+#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description)  // empty
+#define ABSL_ANNOTATE_THREAD_NAME(name)                              // empty
+#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable)                  // empty
+#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description)    // empty
 
-  #define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
-    AbslAnnotateMemoryIsUninitialized(__FILE__, __LINE__, address, size)
+#endif  // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
+
+// -------------------------------------------------------------------------
+// Define memory annotations.
+
+#if ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 1
+
+#include <sanitizer/msan_interface.h>
+
+#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
+  __msan_unpoison(address, size)
+
+#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
+  __msan_allocated_memory(address, size)
+
+#else  // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 0
+
+#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 1
+#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
+  do {                                                     \
+    (void)(address);                                       \
+    (void)(size);                                          \
+  } while (0)
+#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
+  do {                                                       \
+    (void)(address);                                         \
+    (void)(size);                                            \
+  } while (0)
 #else
-  #define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */
-  #define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) /* empty */
-#endif  /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED || MEMORY_SANITIZER */
 
-#if defined(__clang__) && !defined(SWIG)
+#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size)    // empty
+#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size)  // empty
 
-  #if ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0
-    #define ABSL_ANNOTALYSIS_ENABLED
-  #endif
-
-  /* When running in opt-mode, GCC will issue a warning, if these attributes are
-     compiled. Only include them when compiling using Clang. */
-  #define ABSL_ATTRIBUTE_IGNORE_READS_BEGIN \
-      __attribute((exclusive_lock_function("*")))
-  #define ABSL_ATTRIBUTE_IGNORE_READS_END \
-      __attribute((unlock_function("*")))
-#else
-  #define ABSL_ATTRIBUTE_IGNORE_READS_BEGIN  /* empty */
-  #define ABSL_ATTRIBUTE_IGNORE_READS_END  /* empty */
-#endif  /* defined(__clang__) && ... */
-
-#if (ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0) || defined(ABSL_ANNOTALYSIS_ENABLED)
-  #define ABSL_ANNOTATIONS_ENABLED
 #endif
 
-#if (ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0)
+#endif  // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
 
-  /* Request the analysis tool to ignore all reads in the current thread
-     until ABSL_ANNOTATE_IGNORE_READS_END is called.
-     Useful to ignore intentional racey reads, while still checking
-     other reads and all writes.
-     See also ABSL_ANNOTATE_UNPROTECTED_READ. */
-  #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
-    AbslAnnotateIgnoreReadsBegin(__FILE__, __LINE__)
+// -------------------------------------------------------------------------
+// Define IGNORE_READS_BEGIN/_END attributes.
 
-  /* Stop ignoring reads. */
-  #define ABSL_ANNOTATE_IGNORE_READS_END() \
-    AbslAnnotateIgnoreReadsEnd(__FILE__, __LINE__)
+#if ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED == 1
 
-  /* Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead. */
-  #define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
-    AbslAnnotateIgnoreWritesBegin(__FILE__, __LINE__)
+#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \
+  __attribute((exclusive_lock_function("*")))
+#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \
+  __attribute((unlock_function("*")))
 
-  /* Stop ignoring writes. */
-  #define ABSL_ANNOTATE_IGNORE_WRITES_END() \
-    AbslAnnotateIgnoreWritesEnd(__FILE__, __LINE__)
+#else  // ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED == 0
 
-/* Clang provides limited support for static thread-safety analysis
-   through a feature called Annotalysis. We configure macro-definitions
-   according to whether Annotalysis support is available. */
-#elif defined(ABSL_ANNOTALYSIS_ENABLED)
+#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE  // empty
+#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE    // empty
 
-  #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
-    AbslStaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__)
+#endif  // ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED
 
-  #define ABSL_ANNOTATE_IGNORE_READS_END() \
-    AbslStaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__)
+// -------------------------------------------------------------------------
+// Define IGNORE_READS_BEGIN/_END annotations.
 
-  #define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
-    AbslStaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__)
+#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1
 
-  #define ABSL_ANNOTATE_IGNORE_WRITES_END() \
-    AbslStaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__)
+// Request the analysis tool to ignore all reads in the current thread until
+// ABSL_ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey
+// reads, while still checking other reads and all writes.
+// See also ABSL_ANNOTATE_UNPROTECTED_READ.
+#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslAnnotateIgnoreReadsBegin)(__FILE__, __LINE__)
+
+// Stop ignoring reads.
+#define ABSL_ANNOTATE_IGNORE_READS_END() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslAnnotateIgnoreReadsEnd)(__FILE__, __LINE__)
+
+// Function prototypes of annotations provided by the compiler-based sanitizer
+// implementation.
+ABSL_INTERNAL_BEGIN_EXTERN_C
+void AbslAnnotateIgnoreReadsBegin(const char* file, int line)
+    ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE;
+void AbslAnnotateIgnoreReadsEnd(const char* file,
+                            int line) ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE;
+ABSL_INTERNAL_END_EXTERN_C
+
+#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED)
+
+// When Annotalysis is enabled without Dynamic Annotations, the use of
+// static-inline functions allows the annotations to be read at compile-time,
+// while still letting the compiler elide the functions from the final build.
+//
+// TODO(delesley) -- The exclusive lock here ignores writes as well, but
+// allows IGNORE_READS_AND_WRITES to work properly.
+
+#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsBegin)()
+
+#define ABSL_ANNOTATE_IGNORE_READS_END() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsEnd)()
+
+ABSL_INTERNAL_STATIC_INLINE void AbslInternalAnnotateIgnoreReadsBegin()
+    ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE {}
+
+ABSL_INTERNAL_STATIC_INLINE void AbslInternalAnnotateIgnoreReadsEnd()
+    ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE {}
 
 #else
-  #define ABSL_ANNOTATE_IGNORE_READS_BEGIN()  /* empty */
-  #define ABSL_ANNOTATE_IGNORE_READS_END()  /* empty */
-  #define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN()  /* empty */
-  #define ABSL_ANNOTATE_IGNORE_WRITES_END()  /* empty */
+
+#define ABSL_ANNOTATE_IGNORE_READS_BEGIN()  // empty
+#define ABSL_ANNOTATE_IGNORE_READS_END()    // empty
+
 #endif
 
-/* Implement the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
-   primitive annotations defined above. */
-#if defined(ABSL_ANNOTATIONS_ENABLED)
+// -------------------------------------------------------------------------
+// Define IGNORE_WRITES_BEGIN/_END annotations.
 
-  /* Start ignoring all memory accesses (both reads and writes). */
-  #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
-    do {                                           \
-      ABSL_ANNOTATE_IGNORE_READS_BEGIN();               \
-      ABSL_ANNOTATE_IGNORE_WRITES_BEGIN();              \
-    }while (0)
+#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1
 
-  /* Stop ignoring both reads and writes. */
-  #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END()   \
-    do {                                           \
-      ABSL_ANNOTATE_IGNORE_WRITES_END();                \
-      ABSL_ANNOTATE_IGNORE_READS_END();                 \
-    }while (0)
+// Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead.
+#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslAnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
+
+// Stop ignoring writes.
+#define ABSL_ANNOTATE_IGNORE_WRITES_END() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslAnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
+
+// Function prototypes of annotations provided by the compiler-based sanitizer
+// implementation.
+ABSL_INTERNAL_BEGIN_EXTERN_C
+void AbslAnnotateIgnoreWritesBegin(const char* file, int line);
+void AbslAnnotateIgnoreWritesEnd(const char* file, int line);
+ABSL_INTERNAL_END_EXTERN_C
 
 #else
-  #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN()  /* empty */
-  #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END()  /* empty */
+
+#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN()  // empty
+#define ABSL_ANNOTATE_IGNORE_WRITES_END()    // empty
+
 #endif
 
-/* Use the macros above rather than using these functions directly. */
-#include <stddef.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-void AbslAnnotateRWLockCreate(const char *file, int line,
-                          const volatile void *lock);
-void AbslAnnotateRWLockCreateStatic(const char *file, int line,
-                          const volatile void *lock);
-void AbslAnnotateRWLockDestroy(const char *file, int line,
-                           const volatile void *lock);
-void AbslAnnotateRWLockAcquired(const char *file, int line,
-                            const volatile void *lock, long is_w);  /* NOLINT */
-void AbslAnnotateRWLockReleased(const char *file, int line,
-                            const volatile void *lock, long is_w);  /* NOLINT */
-void AbslAnnotateBenignRace(const char *file, int line,
-                        const volatile void *address,
-                        const char *description);
-void AbslAnnotateBenignRaceSized(const char *file, int line,
-                        const volatile void *address,
-                        size_t size,
-                        const char *description);
-void AbslAnnotateThreadName(const char *file, int line,
-                        const char *name);
-void AbslAnnotateEnableRaceDetection(const char *file, int line, int enable);
-void AbslAnnotateMemoryIsInitialized(const char *file, int line,
-                                 const volatile void *mem, size_t size);
-void AbslAnnotateMemoryIsUninitialized(const char *file, int line,
-                                   const volatile void *mem, size_t size);
+// -------------------------------------------------------------------------
+// Define the ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
+// primitive annotations defined above.
+//
+//     Instead of doing
+//        ABSL_ANNOTATE_IGNORE_READS_BEGIN();
+//        ... = x;
+//        ABSL_ANNOTATE_IGNORE_READS_END();
+//     one can use
+//        ... = ABSL_ANNOTATE_UNPROTECTED_READ(x);
 
-/* Annotations expand to these functions, when Dynamic Annotations are enabled.
-   These functions are either implemented as no-op calls, if no Sanitizer is
-   attached, or provided with externally-linked implementations by a library
-   like ThreadSanitizer. */
-void AbslAnnotateIgnoreReadsBegin(const char *file, int line)
-    ABSL_ATTRIBUTE_IGNORE_READS_BEGIN;
-void AbslAnnotateIgnoreReadsEnd(const char *file, int line)
-    ABSL_ATTRIBUTE_IGNORE_READS_END;
-void AbslAnnotateIgnoreWritesBegin(const char *file, int line);
-void AbslAnnotateIgnoreWritesEnd(const char *file, int line);
+#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED)
 
-#if defined(ABSL_ANNOTALYSIS_ENABLED)
-/* When Annotalysis is enabled without Dynamic Annotations, the use of
-   static-inline functions allows the annotations to be read at compile-time,
-   while still letting the compiler elide the functions from the final build.
+// Start ignoring all memory accesses (both reads and writes).
+#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
+  do {                                                \
+    ABSL_ANNOTATE_IGNORE_READS_BEGIN();               \
+    ABSL_ANNOTATE_IGNORE_WRITES_BEGIN();              \
+  } while (0)
 
-   TODO(delesley) -- The exclusive lock here ignores writes as well, but
-   allows IGNORE_READS_AND_WRITES to work properly. */
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-function"
-static inline void AbslStaticAnnotateIgnoreReadsBegin(const char *file, int line)
-    ABSL_ATTRIBUTE_IGNORE_READS_BEGIN { (void)file; (void)line; }
-static inline void AbslStaticAnnotateIgnoreReadsEnd(const char *file, int line)
-    ABSL_ATTRIBUTE_IGNORE_READS_END { (void)file; (void)line; }
-static inline void AbslStaticAnnotateIgnoreWritesBegin(
-    const char *file, int line) { (void)file; (void)line; }
-static inline void AbslStaticAnnotateIgnoreWritesEnd(
-    const char *file, int line) { (void)file; (void)line; }
-#pragma GCC diagnostic pop
-#endif
-
-/* Return non-zero value if running under valgrind.
-
-  If "valgrind.h" is included into dynamic_annotations.cc,
-  the regular valgrind mechanism will be used.
-  See http://valgrind.org/docs/manual/manual-core-adv.html about
-  RUNNING_ON_VALGRIND and other valgrind "client requests".
-  The file "valgrind.h" may be obtained by doing
-     svn co svn://svn.valgrind.org/valgrind/trunk/include
-
-  If for some reason you can't use "valgrind.h" or want to fake valgrind,
-  there are two ways to make this function return non-zero:
-    - Use environment variable: export RUNNING_ON_VALGRIND=1
-    - Make your tool intercept the function AbslRunningOnValgrind() and
-      change its return value.
- */
-int AbslRunningOnValgrind(void);
-
-/* AbslValgrindSlowdown returns:
-    * 1.0, if (AbslRunningOnValgrind() == 0)
-    * 50.0, if (AbslRunningOnValgrind() != 0 && getenv("VALGRIND_SLOWDOWN") == NULL)
-    * atof(getenv("VALGRIND_SLOWDOWN")) otherwise
-   This function can be used to scale timeout values:
-   EXAMPLE:
-   for (;;) {
-     DoExpensiveBackgroundTask();
-     SleepForSeconds(5 * AbslValgrindSlowdown());
-   }
- */
-double AbslValgrindSlowdown(void);
+// Stop ignoring both reads and writes.
+#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() \
+  do {                                              \
+    ABSL_ANNOTATE_IGNORE_WRITES_END();              \
+    ABSL_ANNOTATE_IGNORE_READS_END();               \
+  } while (0)
 
 #ifdef __cplusplus
-}
-#endif
+// ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+#define ABSL_ANNOTATE_UNPROTECTED_READ(x) \
+  absl::base_internal::AnnotateUnprotectedRead(x)
 
-/* ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
 
-     Instead of doing
-        ABSL_ANNOTATE_IGNORE_READS_BEGIN();
-        ... = x;
-        ABSL_ANNOTATE_IGNORE_READS_END();
-     one can use
-        ... = ABSL_ANNOTATE_UNPROTECTED_READ(x); */
-#if defined(__cplusplus) && defined(ABSL_ANNOTATIONS_ENABLED)
 template <typename T>
-inline T ABSL_ANNOTATE_UNPROTECTED_READ(const volatile T &x) { /* NOLINT */
+inline T AnnotateUnprotectedRead(const volatile T& x) {  // NOLINT
   ABSL_ANNOTATE_IGNORE_READS_BEGIN();
   T res = x;
   ABSL_ANNOTATE_IGNORE_READS_END();
   return res;
-  }
-#else
-  #define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x)
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
 #endif
 
-#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus)
-  /* Apply ABSL_ANNOTATE_BENIGN_RACE_SIZED to a static variable. */
-  #define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description)        \
-    namespace {                                                       \
-      class static_var ## _annotator {                                \
-       public:                                                        \
-        static_var ## _annotator() {                                  \
-          ABSL_ANNOTATE_BENIGN_RACE_SIZED(&static_var,                     \
-                                      sizeof(static_var),             \
-            # static_var ": " description);                           \
-        }                                                             \
-      };                                                              \
-      static static_var ## _annotator the ## static_var ## _annotator;\
-    }  // namespace
-#else /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0 */
-  #define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description)  /* empty */
-#endif /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED */
+#else
+
+#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN()  // empty
+#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END()    // empty
+#define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x)
+
+#endif
+
+ABSL_INTERNAL_BEGIN_EXTERN_C
+
+// -------------------------------------------------------------------------
+// Return non-zero value if running under valgrind.
+//
+//  If "valgrind.h" is included into dynamic_annotations.cc,
+//  the regular valgrind mechanism will be used.
+//  See http://valgrind.org/docs/manual/manual-core-adv.html about
+//  RUNNING_ON_VALGRIND and other valgrind "client requests".
+//  The file "valgrind.h" may be obtained by doing
+//     svn co svn://svn.valgrind.org/valgrind/trunk/include
+//
+//  If for some reason you can't use "valgrind.h" or want to fake valgrind,
+//  there are two ways to make this function return non-zero:
+//    - Use environment variable: export RUNNING_ON_VALGRIND=1
+//    - Make your tool intercept the function AbslRunningOnValgrind() and
+//      change its return value.
+//
+int AbslRunningOnValgrind(void);
+
+// AbslValgrindSlowdown returns:
+//    * 1.0, if (AbslRunningOnValgrind() == 0)
+//    * 50.0, if (AbslRunningOnValgrind() != 0 && getenv("VALGRIND_SLOWDOWN") ==
+//    NULL)
+//    * atof(getenv("VALGRIND_SLOWDOWN")) otherwise
+//   This function can be used to scale timeout values:
+//   EXAMPLE:
+//   for (;;) {
+//     DoExpensiveBackgroundTask();
+//     SleepForSeconds(5 * AbslValgrindSlowdown());
+//   }
+//
+double AbslValgrindSlowdown(void);
+
+ABSL_INTERNAL_END_EXTERN_C
+
+// -------------------------------------------------------------------------
+// Address sanitizer annotations
 
 #ifdef ADDRESS_SANITIZER
-/* Describe the current state of a contiguous container such as e.g.
- * std::vector or std::string. For more details see
- * sanitizer/common_interface_defs.h, which is provided by the compiler. */
+// Describe the current state of a contiguous container such as e.g.
+// std::vector or std::string. For more details see
+// sanitizer/common_interface_defs.h, which is provided by the compiler.
 #include <sanitizer/common_interface_defs.h>
+
 #define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
   __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
-#define ABSL_ADDRESS_SANITIZER_REDZONE(name)         \
-  struct { char x[8] __attribute__ ((aligned (8))); } name
+#define ABSL_ADDRESS_SANITIZER_REDZONE(name) \
+  struct {                                   \
+    char x[8] __attribute__((aligned(8)));   \
+  } name
+
 #else
+
 #define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)
 #define ABSL_ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "")
+
 #endif  // ADDRESS_SANITIZER
 
-/* Undefine the macros intended only in this file. */
-#undef ABSL_ANNOTALYSIS_ENABLED
-#undef ABSL_ANNOTATIONS_ENABLED
-#undef ABSL_ATTRIBUTE_IGNORE_READS_BEGIN
-#undef ABSL_ATTRIBUTE_IGNORE_READS_END
+// -------------------------------------------------------------------------
+// Undefine the macros intended only for this file.
 
-#endif  /* ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ */
+#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED
+#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_BEGIN_EXTERN_C
+#undef ABSL_INTERNAL_END_EXTERN_C
+#undef ABSL_INTERNAL_STATIC_INLINE
+
+#endif  // ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
diff --git a/third_party/abseil-cpp/absl/container/internal/unordered_map_modifiers_test.h b/third_party/abseil-cpp/absl/container/internal/unordered_map_modifiers_test.h
index b8c513f1..8c9ca77 100644
--- a/third_party/abseil-cpp/absl/container/internal/unordered_map_modifiers_test.h
+++ b/third_party/abseil-cpp/absl/container/internal/unordered_map_modifiers_test.h
@@ -286,6 +286,8 @@
   }
 };
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniquePtrModifiersTest);
+
 TYPED_TEST_SUITE_P(UniquePtrModifiersTest);
 
 // Test that we do not move from rvalue arguments if an insertion does not
diff --git a/third_party/abseil-cpp/absl/flags/BUILD.bazel b/third_party/abseil-cpp/absl/flags/BUILD.bazel
index 2d6f799..6ffd07c 100644
--- a/third_party/abseil-cpp/absl/flags/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/flags/BUILD.bazel
@@ -114,9 +114,7 @@
     visibility = ["//visibility:private"],
     deps = [
         "//absl/base:config",
-        "//absl/base:core_headers",
         "//absl/base:fast_type_id",
-        "//absl/strings",
     ],
 )
 
@@ -132,6 +130,9 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":commandlineflag_internal",
+        "//absl/base:config",
+        "//absl/base:fast_type_id",
+        "//absl/strings",
         "//absl/types:optional",
     ],
 )
@@ -149,7 +150,12 @@
     visibility = [
         "//absl/flags:__pkg__",
     ],
-    deps = [":commandlineflag"],
+    deps = [
+        ":commandlineflag",
+        ":commandlineflag_internal",
+        "//absl/base:config",
+        "//absl/strings",
+    ],
 )
 
 cc_library(
@@ -193,6 +199,7 @@
     visibility = ["//absl/base:__subpackages__"],
     deps = [
         ":commandlineflag",
+        ":commandlineflag_internal",
         ":config",
         ":marshalling",
         ":registry",
@@ -203,6 +210,7 @@
         "//absl/meta:type_traits",
         "//absl/strings",
         "//absl/synchronization",
+        "//absl/utility",
     ],
 )
 
@@ -220,7 +228,6 @@
     deps = [
         ":config",
         ":flag_internal",
-        ":marshalling",
         ":registry",
         "//absl/base",
         "//absl/base:config",
@@ -287,6 +294,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":commandlineflag",
+        ":commandlineflag_internal",
         ":config",
         ":flag",
         ":flag_internal",
@@ -315,6 +323,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":commandlineflag",
+        ":commandlineflag_internal",
         ":config",
         ":flag",
         ":private_handle_accessor",
@@ -352,6 +361,7 @@
         ":config",
         ":flag",
         ":flag_internal",
+        ":marshalling",
         ":registry",
         "//absl/base:core_headers",
         "//absl/base:malloc_internal",
@@ -372,6 +382,8 @@
     visibility = ["//visibility:private"],
     deps = [
         ":flag",
+        ":marshalling",
+        "//absl/strings",
         "//absl/time",
         "//absl/types:optional",
         "@com_github_google_benchmark//:benchmark_main",
@@ -450,8 +462,8 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":commandlineflag_internal",
         ":flag",
-        ":marshalling",
         ":registry",
         "//absl/memory",
         "@com_google_googletest//:gtest_main",
@@ -492,7 +504,6 @@
         ":registry",
         ":usage",
         ":usage_internal",
-        "//absl/memory",
         "//absl/strings",
         "@com_google_googletest//:gtest",
     ],
diff --git a/third_party/abseil-cpp/absl/flags/BUILD.gn b/third_party/abseil-cpp/absl/flags/BUILD.gn
index 599c8aac..3a6eca1 100644
--- a/third_party/abseil-cpp/absl/flags/BUILD.gn
+++ b/third_party/abseil-cpp/absl/flags/BUILD.gn
@@ -70,9 +70,7 @@
   public = [ "internal/commandlineflag.h" ]
   deps = [
     "//third_party/abseil-cpp/absl/base:config",
-    "//third_party/abseil-cpp/absl/base:core_headers",
     "//third_party/abseil-cpp/absl/base:fast_type_id",
-    "//third_party/abseil-cpp/absl/strings",
   ]
   visibility = []
   visibility += [ ":*" ]
@@ -84,6 +82,9 @@
   public = [ "commandlineflag.h" ]
   deps = [
     ":commandlineflag_internal",
+    "//third_party/abseil-cpp/absl/base:config",
+    "//third_party/abseil-cpp/absl/base:fast_type_id",
+    "//third_party/abseil-cpp/absl/strings",
     "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
@@ -93,7 +94,10 @@
   sources = [ "internal/private_handle_accessor.cc" ]
   public = [ "internal/private_handle_accessor.h" ]
   deps = [
-      ":commandlineflag",
+    ":commandlineflag",
+    ":commandlineflag_internal",
+    "//third_party/abseil-cpp/absl/base:config",
+    "//third_party/abseil-cpp/absl/strings",
   ]
   visibility = []
   visibility += [ ":*" ]
@@ -130,6 +134,7 @@
   public = [ "internal/flag.h" ]
   deps = [
     ":commandlineflag",
+    ":commandlineflag_internal",
     ":config",
     ":marshalling",
     ":registry",
@@ -140,6 +145,7 @@
     "//third_party/abseil-cpp/absl/meta:type_traits",
     "//third_party/abseil-cpp/absl/strings",
     "//third_party/abseil-cpp/absl/synchronization",
+    "//third_party/abseil-cpp/absl/utility",
   ]
   visibility = []
   visibility += [
@@ -158,7 +164,6 @@
   deps = [
     ":config",
     ":flag_internal",
-    ":marshalling",
     ":registry",
     "//third_party/abseil-cpp/absl/base",
     "//third_party/abseil-cpp/absl/base:config",
@@ -210,6 +215,7 @@
   ]
   deps = [
     ":commandlineflag",
+    ":commandlineflag_internal",
     ":config",
     ":flag",
     ":flag_internal",
diff --git a/third_party/abseil-cpp/absl/flags/CMakeLists.txt b/third_party/abseil-cpp/absl/flags/CMakeLists.txt
index 6ecf3b48..2dc7cf4 100644
--- a/third_party/abseil-cpp/absl/flags/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/flags/CMakeLists.txt
@@ -103,9 +103,7 @@
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::config
-    absl::core_headers
     absl::fast_type_id
-    absl::strings
 )
 
 absl_cc_library(
@@ -120,8 +118,11 @@
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
+    absl::config
+    absl::fast_type_id
     absl::flags_commandlineflag_internal
     absl::optional
+    absl::strings
 )
 
 # Internal-only target, do not depend on directly.
@@ -137,7 +138,10 @@
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
+    absl::config
     absl::flags_commandlineflag
+    absl::flags_commandlineflag_internal
+    absl::strings
 )
 
 # Internal-only target, do not depend on directly.
@@ -180,11 +184,13 @@
   DEPS
     absl::base
     absl::config
+    absl::flags_commandlineflag_internal
     absl::flags_config
     absl::flags_marshalling
     absl::flags_registry
     absl::synchronization
     absl::meta
+    absl::utility
   PUBLIC
 )
 
@@ -205,7 +211,6 @@
     absl::flags_commandlineflag
     absl::flags_config
     absl::flags_internal
-    absl::flags_marshalling
     absl::flags_registry
     absl::base
     absl::core_headers
@@ -275,6 +280,7 @@
     absl::flags_config
     absl::flags
     absl::flags_commandlineflag
+    absl::flags_commandlineflag_internal
     absl::flags_internal
     absl::flags_private_handle_accessor
     absl::flags_program_name
@@ -297,6 +303,7 @@
   DEPS
     absl::flags
     absl::flags_commandlineflag
+    absl::flags_commandlineflag_internal
     absl::flags_config
     absl::flags_private_handle_accessor
     absl::flags_registry
@@ -330,6 +337,7 @@
     absl::flags
     absl::flags_config
     absl::flags_internal
+    absl::flags_marshalling
     absl::flags_registry
     absl::strings
     absl::time
@@ -399,8 +407,8 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
+    absl::flags_commandlineflag_internal
     absl::flags
-    absl::flags_marshalling
     absl::flags_registry
     absl::memory
     absl::strings
@@ -437,7 +445,6 @@
     absl::flags_parse
     absl::flags_registry
     absl::flags_usage
-    absl::memory
     absl::strings
     gtest
 )
diff --git a/third_party/abseil-cpp/absl/flags/commandlineflag.cc b/third_party/abseil-cpp/absl/flags/commandlineflag.cc
index cea5723..217b2d87 100644
--- a/third_party/abseil-cpp/absl/flags/commandlineflag.cc
+++ b/third_party/abseil-cpp/absl/flags/commandlineflag.cc
@@ -15,6 +15,12 @@
 
 #include "absl/flags/commandlineflag.h"
 
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/strings/string_view.h"
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
diff --git a/third_party/abseil-cpp/absl/flags/commandlineflag.h b/third_party/abseil-cpp/absl/flags/commandlineflag.h
index 43055d041..7e21d05 100644
--- a/third_party/abseil-cpp/absl/flags/commandlineflag.h
+++ b/third_party/abseil-cpp/absl/flags/commandlineflag.h
@@ -26,7 +26,13 @@
 #ifndef ABSL_FLAGS_COMMANDLINEFLAG_H_
 #define ABSL_FLAGS_COMMANDLINEFLAG_H_
 
+#include <memory>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/fast_type_id.h"
 #include "absl/flags/internal/commandlineflag.h"
+#include "absl/strings/string_view.h"
 #include "absl/types/optional.h"
 
 namespace absl {
diff --git a/third_party/abseil-cpp/absl/flags/commandlineflag_test.cc b/third_party/abseil-cpp/absl/flags/commandlineflag_test.cc
index 4b9718e..570bbe2f 100644
--- a/third_party/abseil-cpp/absl/flags/commandlineflag_test.cc
+++ b/third_party/abseil-cpp/absl/flags/commandlineflag_test.cc
@@ -20,6 +20,7 @@
 
 #include "gtest/gtest.h"
 #include "absl/flags/flag.h"
+#include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/private_handle_accessor.h"
 #include "absl/flags/internal/registry.h"
 #include "absl/flags/usage_config.h"
diff --git a/third_party/abseil-cpp/absl/flags/declare.h b/third_party/abseil-cpp/absl/flags/declare.h
index 0f8cc6a5..b9794d8 100644
--- a/third_party/abseil-cpp/absl/flags/declare.h
+++ b/third_party/abseil-cpp/absl/flags/declare.h
@@ -26,7 +26,6 @@
 #define ABSL_FLAGS_DECLARE_H_
 
 #include "absl/base/config.h"
-#include "absl/strings/string_view.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
diff --git a/third_party/abseil-cpp/absl/flags/flag.h b/third_party/abseil-cpp/absl/flags/flag.h
index dd36e6c7..90dc2894df 100644
--- a/third_party/abseil-cpp/absl/flags/flag.h
+++ b/third_party/abseil-cpp/absl/flags/flag.h
@@ -33,13 +33,11 @@
 #include <type_traits>
 
 #include "absl/base/attributes.h"
-#include "absl/base/casts.h"
 #include "absl/base/config.h"
+#include "absl/base/optimization.h"
 #include "absl/flags/config.h"
-#include "absl/flags/declare.h"
 #include "absl/flags/internal/flag.h"
 #include "absl/flags/internal/registry.h"
-#include "absl/flags/marshalling.h"
 #include "absl/strings/string_view.h"
 
 namespace absl {
@@ -150,6 +148,8 @@
   void Set(const T& v) { GetImpl().Set(v); }
   void InvokeCallback() { GetImpl().InvokeCallback(); }
 
+  const CommandLineFlag& Reflect() const { return GetImpl().Reflect(); }
+
   // The data members are logically private, but they need to be public for
   // this to be an aggregate type.
   const char* name_;
@@ -204,6 +204,21 @@
   flag->Set(value);
 }
 
+// GetFlagReflectionHandle()
+//
+// Returns the reflection handle corresponding to specified Abseil Flag
+// instance. Use this handle to access flag's reflection information, like name,
+// location, default value etc.
+//
+// Example:
+//
+//   std::string = absl::GetFlagReflectionHandle(FLAGS_count).DefaultValue();
+
+template <typename T>
+const CommandLineFlag& GetFlagReflectionHandle(const absl::Flag<T>& f) {
+  return f.Reflect();
+}
+
 ABSL_NAMESPACE_END
 }  // namespace absl
 
diff --git a/third_party/abseil-cpp/absl/flags/flag_benchmark.cc b/third_party/abseil-cpp/absl/flags/flag_benchmark.cc
index ff95bb5..7b52c9bc 100644
--- a/third_party/abseil-cpp/absl/flags/flag_benchmark.cc
+++ b/third_party/abseil-cpp/absl/flags/flag_benchmark.cc
@@ -13,7 +13,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
 #include "absl/flags/flag.h"
+#include "absl/flags/marshalling.h"
+#include "absl/strings/string_view.h"
 #include "absl/time/time.h"
 #include "absl/types/optional.h"
 #include "benchmark/benchmark.h"
diff --git a/third_party/abseil-cpp/absl/flags/flag_test.cc b/third_party/abseil-cpp/absl/flags/flag_test.cc
index 58a0799..71661d39 100644
--- a/third_party/abseil-cpp/absl/flags/flag_test.cc
+++ b/third_party/abseil-cpp/absl/flags/flag_test.cc
@@ -15,9 +15,11 @@
 
 #include "absl/flags/flag.h"
 
+#include <stddef.h>
 #include <stdint.h>
 
 #include <cmath>
+#include <new>
 #include <string>
 #include <thread>  // NOLINT
 #include <vector>
@@ -28,6 +30,7 @@
 #include "absl/flags/declare.h"
 #include "absl/flags/internal/flag.h"
 #include "absl/flags/internal/registry.h"
+#include "absl/flags/marshalling.h"
 #include "absl/flags/usage_config.h"
 #include "absl/strings/match.h"
 #include "absl/strings/numbers.h"
@@ -44,6 +47,9 @@
 namespace flags = absl::flags_internal;
 
 std::string TestHelpMsg() { return "dynamic help"; }
+#if defined(_MSC_VER) && !defined(__clang__)
+std::string TestLiteralHelpMsg() { return "literal help"; }
+#endif
 template <typename T>
 void TestMakeDflt(void* dst) {
   new (dst) T{};
@@ -127,15 +133,29 @@
 
 using String = std::string;
 
-#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind)                      \
-  constexpr flags::FlagDefaultArg f1default##T{                          \
-      flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind};   \
-  constexpr flags::Flag<T> f1##T("f1", "file", help_arg, f1default##T);  \
-  ABSL_CONST_INIT flags::Flag<T> f2##T(                                  \
-      "f2", "file",                                                      \
-      {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \
-      flags::FlagDefaultArg{flags::FlagDefaultSrc(&TestMakeDflt<T>),     \
-                            flags::FlagDefaultKind::kGenFunc})
+#if !defined(_MSC_VER) || defined(__clang__)
+#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind)                        \
+  constexpr flags::FlagDefaultArg f1default##T{                            \
+      flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind};     \
+  constexpr absl::Flag<T> f1##T{"f1", "file", help_arg, f1default##T};     \
+  ABSL_CONST_INIT absl::Flag<T> f2##T {                                    \
+    "f2", "file",                                                          \
+        {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \
+        flags::FlagDefaultArg {                                            \
+      flags::FlagDefaultSrc(&TestMakeDflt<T>),                             \
+          flags::FlagDefaultKind::kGenFunc                                 \
+    }                                                                      \
+  }
+#else
+#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind)                    \
+  constexpr flags::FlagDefaultArg f1default##T{                        \
+      flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind}; \
+  constexpr absl::Flag<T> f1##T{"f1", "file", &TestLiteralHelpMsg,     \
+                                &TestMakeDflt<T>};                     \
+  ABSL_CONST_INIT absl::Flag<T> f2##T {                                \
+    "f2", "file", &TestHelpMsg, &TestMakeDflt<T>                       \
+  }
+#endif
 
 DEFINE_CONSTRUCTED_FLAG(bool, true, kOneWord);
 DEFINE_CONSTRUCTED_FLAG(int16_t, 1, kOneWord);
@@ -150,16 +170,17 @@
 DEFINE_CONSTRUCTED_FLAG(UDT, &TestMakeDflt<UDT>, kGenFunc);
 
 template <typename T>
-bool TestConstructionFor(const flags::Flag<T>& f1, flags::Flag<T>& f2) {
-  EXPECT_EQ(f1.Name(), "f1");
-  EXPECT_EQ(f1.Help(), "literal help");
-  EXPECT_EQ(f1.Filename(), "file");
+bool TestConstructionFor(const absl::Flag<T>& f1, absl::Flag<T>& f2) {
+  EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Name(), "f1");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Help(), "literal help");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Filename(), "file");
 
-  flags::FlagRegistrar<T, false>(f2).OnUpdate(TestCallback);
+  flags::FlagRegistrar<T, false>(ABSL_FLAG_IMPL_FLAG_PTR(f2))
+      .OnUpdate(TestCallback);
 
-  EXPECT_EQ(f2.Name(), "f2");
-  EXPECT_EQ(f2.Help(), "dynamic help");
-  EXPECT_EQ(f2.Filename(), "file");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Name(), "f2");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Help(), "dynamic help");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Filename(), "file");
 
   return true;
 }
@@ -203,18 +224,30 @@
 
 TEST_F(FlagTest, TestFlagDeclaration) {
   // test that we can access flag objects.
-  EXPECT_EQ(FLAGS_test_flag_01.Name(), "test_flag_01");
-  EXPECT_EQ(FLAGS_test_flag_02.Name(), "test_flag_02");
-  EXPECT_EQ(FLAGS_test_flag_03.Name(), "test_flag_03");
-  EXPECT_EQ(FLAGS_test_flag_04.Name(), "test_flag_04");
-  EXPECT_EQ(FLAGS_test_flag_05.Name(), "test_flag_05");
-  EXPECT_EQ(FLAGS_test_flag_06.Name(), "test_flag_06");
-  EXPECT_EQ(FLAGS_test_flag_07.Name(), "test_flag_07");
-  EXPECT_EQ(FLAGS_test_flag_08.Name(), "test_flag_08");
-  EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09");
-  EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10");
-  EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11");
-  EXPECT_EQ(FLAGS_test_flag_12.Name(), "test_flag_12");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Name(),
+            "test_flag_01");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Name(),
+            "test_flag_02");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Name(),
+            "test_flag_03");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Name(),
+            "test_flag_04");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Name(),
+            "test_flag_05");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Name(),
+            "test_flag_06");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Name(),
+            "test_flag_07");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Name(),
+            "test_flag_08");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Name(),
+            "test_flag_09");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Name(),
+            "test_flag_10");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Name(),
+            "test_flag_11");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(),
+            "test_flag_12");
 }
 #endif  // !ABSL_FLAGS_STRIP_NAMES
 
@@ -241,96 +274,168 @@
 TEST_F(FlagTest, TestFlagDefinition) {
   absl::string_view expected_file_name = "absl/flags/flag_test.cc";
 
-  EXPECT_EQ(FLAGS_test_flag_01.Name(), "test_flag_01");
-  EXPECT_EQ(FLAGS_test_flag_01.Help(), "test flag 01");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_01.Filename(), expected_file_name))
-      << FLAGS_test_flag_01.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Name(),
+            "test_flag_01");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Help(),
+            "test flag 01");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_02.Name(), "test_flag_02");
-  EXPECT_EQ(FLAGS_test_flag_02.Help(), "test flag 02");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_02.Filename(), expected_file_name))
-      << FLAGS_test_flag_02.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Name(),
+            "test_flag_02");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Help(),
+            "test flag 02");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_03.Name(), "test_flag_03");
-  EXPECT_EQ(FLAGS_test_flag_03.Help(), "test flag 03");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_03.Filename(), expected_file_name))
-      << FLAGS_test_flag_03.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Name(),
+            "test_flag_03");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Help(),
+            "test flag 03");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_04.Name(), "test_flag_04");
-  EXPECT_EQ(FLAGS_test_flag_04.Help(), "test flag 04");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_04.Filename(), expected_file_name))
-      << FLAGS_test_flag_04.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Name(),
+            "test_flag_04");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Help(),
+            "test flag 04");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_05.Name(), "test_flag_05");
-  EXPECT_EQ(FLAGS_test_flag_05.Help(), "test flag 05");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_05.Filename(), expected_file_name))
-      << FLAGS_test_flag_05.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Name(),
+            "test_flag_05");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Help(),
+            "test flag 05");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_06.Name(), "test_flag_06");
-  EXPECT_EQ(FLAGS_test_flag_06.Help(), "test flag 06");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_06.Filename(), expected_file_name))
-      << FLAGS_test_flag_06.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Name(),
+            "test_flag_06");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Help(),
+            "test flag 06");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_07.Name(), "test_flag_07");
-  EXPECT_EQ(FLAGS_test_flag_07.Help(), "test flag 07");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_07.Filename(), expected_file_name))
-      << FLAGS_test_flag_07.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Name(),
+            "test_flag_07");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Help(),
+            "test flag 07");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_08.Name(), "test_flag_08");
-  EXPECT_EQ(FLAGS_test_flag_08.Help(), "test flag 08");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_08.Filename(), expected_file_name))
-      << FLAGS_test_flag_08.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Name(),
+            "test_flag_08");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Help(),
+            "test flag 08");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09");
-  EXPECT_EQ(FLAGS_test_flag_09.Help(), "test flag 09");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_09.Filename(), expected_file_name))
-      << FLAGS_test_flag_09.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Name(),
+            "test_flag_09");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Help(),
+            "test flag 09");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10");
-  EXPECT_EQ(FLAGS_test_flag_10.Help(), "test flag 10");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_10.Filename(), expected_file_name))
-      << FLAGS_test_flag_10.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Name(),
+            "test_flag_10");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Help(),
+            "test flag 10");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11");
-  EXPECT_EQ(FLAGS_test_flag_11.Help(), "test flag 11");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_11.Filename(), expected_file_name))
-      << FLAGS_test_flag_11.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Name(),
+            "test_flag_11");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Help(),
+            "test flag 11");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Filename();
 
-  EXPECT_EQ(FLAGS_test_flag_12.Name(), "test_flag_12");
-  EXPECT_EQ(FLAGS_test_flag_12.Help(), "test flag 12");
-  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_12.Filename(), expected_file_name))
-      << FLAGS_test_flag_12.Filename();
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(),
+            "test_flag_12");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Help(),
+            "test flag 12");
+  EXPECT_TRUE(absl::EndsWith(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename(),
+      expected_file_name))
+      << absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename();
 }
 #endif  // !ABSL_FLAGS_STRIP_NAMES
 
 // --------------------------------------------------------------------
 
 TEST_F(FlagTest, TestDefault) {
-  EXPECT_EQ(FLAGS_test_flag_01.DefaultValue(), "true");
-  EXPECT_EQ(FLAGS_test_flag_02.DefaultValue(), "1234");
-  EXPECT_EQ(FLAGS_test_flag_03.DefaultValue(), "-34");
-  EXPECT_EQ(FLAGS_test_flag_04.DefaultValue(), "189");
-  EXPECT_EQ(FLAGS_test_flag_05.DefaultValue(), "10765");
-  EXPECT_EQ(FLAGS_test_flag_06.DefaultValue(), "40000");
-  EXPECT_EQ(FLAGS_test_flag_07.DefaultValue(), "-1234567");
-  EXPECT_EQ(FLAGS_test_flag_08.DefaultValue(), "9876543");
-  EXPECT_EQ(FLAGS_test_flag_09.DefaultValue(), "-9.876e-50");
-  EXPECT_EQ(FLAGS_test_flag_10.DefaultValue(), "1.234e+12");
-  EXPECT_EQ(FLAGS_test_flag_11.DefaultValue(), "");
-  EXPECT_EQ(FLAGS_test_flag_12.DefaultValue(), "10m");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).DefaultValue(),
+            "true");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).DefaultValue(),
+            "1234");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).DefaultValue(),
+            "-34");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).DefaultValue(),
+            "189");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).DefaultValue(),
+            "10765");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).DefaultValue(),
+            "40000");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).DefaultValue(),
+            "-1234567");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).DefaultValue(),
+            "9876543");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).DefaultValue(),
+            "-9.876e-50");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).DefaultValue(),
+            "1.234e+12");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).DefaultValue(),
+            "");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).DefaultValue(),
+            "10m");
 
-  EXPECT_EQ(FLAGS_test_flag_01.CurrentValue(), "true");
-  EXPECT_EQ(FLAGS_test_flag_02.CurrentValue(), "1234");
-  EXPECT_EQ(FLAGS_test_flag_03.CurrentValue(), "-34");
-  EXPECT_EQ(FLAGS_test_flag_04.CurrentValue(), "189");
-  EXPECT_EQ(FLAGS_test_flag_05.CurrentValue(), "10765");
-  EXPECT_EQ(FLAGS_test_flag_06.CurrentValue(), "40000");
-  EXPECT_EQ(FLAGS_test_flag_07.CurrentValue(), "-1234567");
-  EXPECT_EQ(FLAGS_test_flag_08.CurrentValue(), "9876543");
-  EXPECT_EQ(FLAGS_test_flag_09.CurrentValue(), "-9.876e-50");
-  EXPECT_EQ(FLAGS_test_flag_10.CurrentValue(), "1.234e+12");
-  EXPECT_EQ(FLAGS_test_flag_11.CurrentValue(), "");
-  EXPECT_EQ(FLAGS_test_flag_12.CurrentValue(), "10m");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).CurrentValue(),
+            "true");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).CurrentValue(),
+            "1234");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).CurrentValue(),
+            "-34");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).CurrentValue(),
+            "189");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).CurrentValue(),
+            "10765");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).CurrentValue(),
+            "40000");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).CurrentValue(),
+            "-1234567");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).CurrentValue(),
+            "9876543");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).CurrentValue(),
+            "-9.876e-50");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).CurrentValue(),
+            "1.234e+12");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).CurrentValue(),
+            "");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).CurrentValue(),
+            "10m");
 
   EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true);
   EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234);
@@ -385,12 +490,18 @@
 namespace {
 
 TEST_F(FlagTest, TestEmptyBracesDefault) {
-  EXPECT_EQ(FLAGS_test_flag_eb_01.DefaultValue(), "false");
-  EXPECT_EQ(FLAGS_test_flag_eb_02.DefaultValue(), "0");
-  EXPECT_EQ(FLAGS_test_flag_eb_03.DefaultValue(), "0");
-  EXPECT_EQ(FLAGS_test_flag_eb_04.DefaultValue(), "0");
-  EXPECT_EQ(FLAGS_test_flag_eb_05.DefaultValue(), "");
-  EXPECT_EQ(FLAGS_test_flag_eb_06.DefaultValue(), "0");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_01).DefaultValue(),
+            "false");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_02).DefaultValue(),
+            "0");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_03).DefaultValue(),
+            "0");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_04).DefaultValue(),
+            "0");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_05).DefaultValue(),
+            "");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_06).DefaultValue(),
+            "0");
 
   EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_01), false);
   EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_02), 0);
@@ -500,8 +611,9 @@
 
 #if !ABSL_FLAGS_STRIP_HELP
 TEST_F(FlagTest, TestNonConstexprHelp) {
-  EXPECT_EQ(FLAGS_test_flag_with_non_const_help.Help(),
-            "test flag non const help");
+  EXPECT_EQ(
+      absl::GetFlagReflectionHandle(FLAGS_test_flag_with_non_const_help).Help(),
+      "test flag non const help");
 }
 #endif  //! ABSL_FLAGS_STRIP_HELP
 
diff --git a/third_party/abseil-cpp/absl/flags/internal/commandlineflag.h b/third_party/abseil-cpp/absl/flags/internal/commandlineflag.h
index 3c149788..cb46fe2 100644
--- a/third_party/abseil-cpp/absl/flags/internal/commandlineflag.h
+++ b/third_party/abseil-cpp/absl/flags/internal/commandlineflag.h
@@ -16,13 +16,8 @@
 #ifndef ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
 #define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
 
-#include <memory>
-#include <string>
-
 #include "absl/base/config.h"
 #include "absl/base/internal/fast_type_id.h"
-#include "absl/base/macros.h"
-#include "absl/strings/string_view.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -33,7 +28,7 @@
 // cases this id is enough to uniquely identify the flag's value type. In a few
 // cases we'll have to resort to using actual RTTI implementation if it is
 // available.
-using FlagFastTypeId = base_internal::FastTypeIdType;
+using FlagFastTypeId = absl::base_internal::FastTypeIdType;
 
 // Options that control SetCommandLineOptionWithMode.
 enum FlagSettingMode {
diff --git a/third_party/abseil-cpp/absl/flags/internal/flag.cc b/third_party/abseil-cpp/absl/flags/internal/flag.cc
index ee9742445..1502e7f1 100644
--- a/third_party/abseil-cpp/absl/flags/internal/flag.cc
+++ b/third_party/abseil-cpp/absl/flags/internal/flag.cc
@@ -15,21 +15,26 @@
 
 #include "absl/flags/internal/flag.h"
 
+#include <assert.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <string.h>
 
+#include <array>
 #include <atomic>
 #include <memory>
+#include <new>
 #include <string>
-#include <vector>
+#include <typeinfo>
 
-#include "absl/base/attributes.h"
+#include "absl/base/call_once.h"
 #include "absl/base/casts.h"
 #include "absl/base/config.h"
-#include "absl/base/const_init.h"
 #include "absl/base/optimization.h"
+#include "absl/flags/config.h"
+#include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/usage_config.h"
+#include "absl/memory/memory.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
 #include "absl/synchronization/mutex.h"
diff --git a/third_party/abseil-cpp/absl/flags/internal/flag.h b/third_party/abseil-cpp/absl/flags/internal/flag.h
index e188580..2cc44e0 100644
--- a/third_party/abseil-cpp/absl/flags/internal/flag.h
+++ b/third_party/abseil-cpp/absl/flags/internal/flag.h
@@ -16,31 +16,36 @@
 #ifndef ABSL_FLAGS_INTERNAL_FLAG_H_
 #define ABSL_FLAGS_INTERNAL_FLAG_H_
 
+#include <stddef.h>
 #include <stdint.h>
 
 #include <atomic>
 #include <cstring>
 #include <memory>
+#include <new>
 #include <string>
 #include <type_traits>
 #include <typeinfo>
 
+#include "absl/base/attributes.h"
 #include "absl/base/call_once.h"
 #include "absl/base/config.h"
+#include "absl/base/optimization.h"
 #include "absl/base/thread_annotations.h"
 #include "absl/flags/commandlineflag.h"
 #include "absl/flags/config.h"
+#include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/registry.h"
 #include "absl/flags/marshalling.h"
-#include "absl/memory/memory.h"
 #include "absl/meta/type_traits.h"
-#include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
 #include "absl/synchronization/mutex.h"
+#include "absl/utility/utility.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
+///////////////////////////////////////////////////////////////////////////////
 // Forward declaration of absl::Flag<T> public API.
 namespace flags_internal {
 template <typename T>
@@ -64,12 +69,15 @@
 template <typename T, typename V>
 void SetFlag(absl::Flag<T>* flag, const V& v);
 
-namespace flags_internal {
+template <typename U>
+const CommandLineFlag& GetFlagReflectionHandle(const absl::Flag<U>& f);
 
 ///////////////////////////////////////////////////////////////////////////////
 // Flag value type operations, eg., parsing, copying, etc. are provided
 // by function specific to that type with a signature matching FlagOpFn.
 
+namespace flags_internal {
+
 enum class FlagOp {
   kAlloc,
   kDelete,
@@ -659,6 +667,13 @@
     impl_.Write(&v);
   }
 
+  template <typename U>
+  friend const CommandLineFlag& absl::GetFlagReflectionHandle(
+      const absl::Flag<U>& f);
+
+  // Access to the reflection.
+  const CommandLineFlag& Reflect() const { return impl_; }
+
   // Flag's data
   // The implementation depends on value_ field to be placed exactly after the
   // impl_ field, so that impl_ can figure out the offset to the value and
diff --git a/third_party/abseil-cpp/absl/flags/internal/parse.h b/third_party/abseil-cpp/absl/flags/internal/parse.h
index d259be7..de706c8 100644
--- a/third_party/abseil-cpp/absl/flags/internal/parse.h
+++ b/third_party/abseil-cpp/absl/flags/internal/parse.h
@@ -21,6 +21,7 @@
 
 #include "absl/base/config.h"
 #include "absl/flags/declare.h"
+#include "absl/strings/string_view.h"
 
 ABSL_DECLARE_FLAG(std::vector<std::string>, flagfile);
 ABSL_DECLARE_FLAG(std::vector<std::string>, fromenv);
diff --git a/third_party/abseil-cpp/absl/flags/internal/path_util.h b/third_party/abseil-cpp/absl/flags/internal/path_util.h
index 365c830..a6594d3 100644
--- a/third_party/abseil-cpp/absl/flags/internal/path_util.h
+++ b/third_party/abseil-cpp/absl/flags/internal/path_util.h
@@ -17,7 +17,6 @@
 #define ABSL_FLAGS_INTERNAL_PATH_UTIL_H_
 
 #include "absl/base/config.h"
-#include "absl/strings/match.h"
 #include "absl/strings/string_view.h"
 
 namespace absl {
diff --git a/third_party/abseil-cpp/absl/flags/internal/private_handle_accessor.cc b/third_party/abseil-cpp/absl/flags/internal/private_handle_accessor.cc
index 24b49136..a7eb58b 100644
--- a/third_party/abseil-cpp/absl/flags/internal/private_handle_accessor.cc
+++ b/third_party/abseil-cpp/absl/flags/internal/private_handle_accessor.cc
@@ -15,6 +15,14 @@
 
 #include "absl/flags/internal/private_handle_accessor.h"
 
+#include <memory>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/flags/commandlineflag.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/strings/string_view.h"
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace flags_internal {
diff --git a/third_party/abseil-cpp/absl/flags/internal/private_handle_accessor.h b/third_party/abseil-cpp/absl/flags/internal/private_handle_accessor.h
index 9a327a07..c64435c 100644
--- a/third_party/abseil-cpp/absl/flags/internal/private_handle_accessor.h
+++ b/third_party/abseil-cpp/absl/flags/internal/private_handle_accessor.h
@@ -16,7 +16,13 @@
 #ifndef ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_
 #define ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_
 
+#include <memory>
+#include <string>
+
+#include "absl/base/config.h"
 #include "absl/flags/commandlineflag.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/strings/string_view.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
diff --git a/third_party/abseil-cpp/absl/flags/internal/registry.cc b/third_party/abseil-cpp/absl/flags/internal/registry.cc
index 4bcebfa..e582d79d 100644
--- a/third_party/abseil-cpp/absl/flags/internal/registry.cc
+++ b/third_party/abseil-cpp/absl/flags/internal/registry.cc
@@ -29,6 +29,7 @@
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/thread_annotations.h"
 #include "absl/flags/commandlineflag.h"
+#include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/private_handle_accessor.h"
 #include "absl/flags/usage_config.h"
 #include "absl/strings/str_cat.h"
diff --git a/third_party/abseil-cpp/absl/flags/internal/registry.h b/third_party/abseil-cpp/absl/flags/internal/registry.h
index a118865..d207c22 100644
--- a/third_party/abseil-cpp/absl/flags/internal/registry.h
+++ b/third_party/abseil-cpp/absl/flags/internal/registry.h
@@ -17,11 +17,9 @@
 #define ABSL_FLAGS_INTERNAL_REGISTRY_H_
 
 #include <functional>
-#include <map>
-#include <string>
 
 #include "absl/base/config.h"
-#include "absl/base/macros.h"
+#include "absl/flags/commandlineflag.h"
 #include "absl/flags/internal/commandlineflag.h"
 #include "absl/strings/string_view.h"
 
@@ -30,8 +28,6 @@
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
-class CommandLineFlag;
-
 namespace flags_internal {
 
 CommandLineFlag* FindCommandLineFlag(absl::string_view name);
diff --git a/third_party/abseil-cpp/absl/flags/internal/type_erased.h b/third_party/abseil-cpp/absl/flags/internal/type_erased.h
index fd9663e2..437a8c2 100644
--- a/third_party/abseil-cpp/absl/flags/internal/type_erased.h
+++ b/third_party/abseil-cpp/absl/flags/internal/type_erased.h
@@ -20,6 +20,7 @@
 
 #include "absl/base/config.h"
 #include "absl/flags/commandlineflag.h"
+#include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/registry.h"
 #include "absl/strings/string_view.h"
 
diff --git a/third_party/abseil-cpp/absl/flags/internal/type_erased_test.cc b/third_party/abseil-cpp/absl/flags/internal/type_erased_test.cc
index bb0ff23e..42f374d 100644
--- a/third_party/abseil-cpp/absl/flags/internal/type_erased_test.cc
+++ b/third_party/abseil-cpp/absl/flags/internal/type_erased_test.cc
@@ -20,8 +20,8 @@
 
 #include "gtest/gtest.h"
 #include "absl/flags/flag.h"
+#include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/registry.h"
-#include "absl/flags/marshalling.h"
 #include "absl/memory/memory.h"
 
 ABSL_FLAG(int, int_flag, 1, "int_flag help");
diff --git a/third_party/abseil-cpp/absl/flags/internal/usage.cc b/third_party/abseil-cpp/absl/flags/internal/usage.cc
index 2a2231a..35b6427 100644
--- a/third_party/abseil-cpp/absl/flags/internal/usage.cc
+++ b/third_party/abseil-cpp/absl/flags/internal/usage.cc
@@ -15,6 +15,8 @@
 
 #include "absl/flags/internal/usage.h"
 
+#include <stdint.h>
+
 #include <functional>
 #include <map>
 #include <ostream>
diff --git a/third_party/abseil-cpp/absl/flags/internal/usage_test.cc b/third_party/abseil-cpp/absl/flags/internal/usage_test.cc
index 8dd3532..53b4d98 100644
--- a/third_party/abseil-cpp/absl/flags/internal/usage_test.cc
+++ b/third_party/abseil-cpp/absl/flags/internal/usage_test.cc
@@ -21,7 +21,6 @@
 #include <string>
 
 #include "gtest/gtest.h"
-#include "absl/flags/declare.h"
 #include "absl/flags/flag.h"
 #include "absl/flags/internal/parse.h"
 #include "absl/flags/internal/path_util.h"
@@ -29,7 +28,6 @@
 #include "absl/flags/internal/registry.h"
 #include "absl/flags/usage.h"
 #include "absl/flags/usage_config.h"
-#include "absl/memory/memory.h"
 #include "absl/strings/match.h"
 #include "absl/strings/string_view.h"
 
diff --git a/third_party/abseil-cpp/absl/flags/parse.cc b/third_party/abseil-cpp/absl/flags/parse.cc
index 1530078..f0a131f2 100644
--- a/third_party/abseil-cpp/absl/flags/parse.cc
+++ b/third_party/abseil-cpp/absl/flags/parse.cc
@@ -37,6 +37,7 @@
 #include "absl/flags/commandlineflag.h"
 #include "absl/flags/config.h"
 #include "absl/flags/flag.h"
+#include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/flag.h"
 #include "absl/flags/internal/parse.h"
 #include "absl/flags/internal/private_handle_accessor.h"
diff --git a/third_party/abseil-cpp/absl/flags/parse.h b/third_party/abseil-cpp/absl/flags/parse.h
index f37b060..929de2cb 100644
--- a/third_party/abseil-cpp/absl/flags/parse.h
+++ b/third_party/abseil-cpp/absl/flags/parse.h
@@ -23,7 +23,6 @@
 #ifndef ABSL_FLAGS_PARSE_H_
 #define ABSL_FLAGS_PARSE_H_
 
-#include <string>
 #include <vector>
 
 #include "absl/base/config.h"
diff --git a/third_party/abseil-cpp/absl/flags/usage_config.cc b/third_party/abseil-cpp/absl/flags/usage_config.cc
index 0d21bce..ae2f548a 100644
--- a/third_party/abseil-cpp/absl/flags/usage_config.cc
+++ b/third_party/abseil-cpp/absl/flags/usage_config.cc
@@ -15,6 +15,7 @@
 
 #include "absl/flags/usage_config.h"
 
+#include <functional>
 #include <iostream>
 #include <string>
 
diff --git a/third_party/abseil-cpp/absl/time/civil_time.cc b/third_party/abseil-cpp/absl/time/civil_time.cc
index c4202c7..bdfe9ce 100644
--- a/third_party/abseil-cpp/absl/time/civil_time.cc
+++ b/third_party/abseil-cpp/absl/time/civil_time.cc
@@ -98,26 +98,26 @@
 }  // namespace
 
 std::string FormatCivilTime(CivilSecond c) {
-  return FormatYearAnd("-%m-%dT%H:%M:%S", c);
+  return FormatYearAnd("-%m-%d%ET%H:%M:%S", c);
 }
 std::string FormatCivilTime(CivilMinute c) {
-  return FormatYearAnd("-%m-%dT%H:%M", c);
+  return FormatYearAnd("-%m-%d%ET%H:%M", c);
 }
 std::string FormatCivilTime(CivilHour c) {
-  return FormatYearAnd("-%m-%dT%H", c);
+  return FormatYearAnd("-%m-%d%ET%H", c);
 }
 std::string FormatCivilTime(CivilDay c) { return FormatYearAnd("-%m-%d", c); }
 std::string FormatCivilTime(CivilMonth c) { return FormatYearAnd("-%m", c); }
 std::string FormatCivilTime(CivilYear c) { return FormatYearAnd("", c); }
 
 bool ParseCivilTime(string_view s, CivilSecond* c) {
-  return ParseYearAnd("-%m-%dT%H:%M:%S", s, c);
+  return ParseYearAnd("-%m-%d%ET%H:%M:%S", s, c);
 }
 bool ParseCivilTime(string_view s, CivilMinute* c) {
-  return ParseYearAnd("-%m-%dT%H:%M", s, c);
+  return ParseYearAnd("-%m-%d%ET%H:%M", s, c);
 }
 bool ParseCivilTime(string_view s, CivilHour* c) {
-  return ParseYearAnd("-%m-%dT%H", s, c);
+  return ParseYearAnd("-%m-%d%ET%H", s, c);
 }
 bool ParseCivilTime(string_view s, CivilDay* c) {
   return ParseYearAnd("-%m-%d", s, c);
diff --git a/third_party/abseil-cpp/absl/time/format.cc b/third_party/abseil-cpp/absl/time/format.cc
index 228940e..4005fb70 100644
--- a/third_party/abseil-cpp/absl/time/format.cc
+++ b/third_party/abseil-cpp/absl/time/format.cc
@@ -27,14 +27,11 @@
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
-ABSL_DLL extern const char RFC3339_full[] =
-    "%Y-%m-%dT%H:%M:%E*S%Ez";
-ABSL_DLL extern const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez";
+ABSL_DLL extern const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez";
+ABSL_DLL extern const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
 
-ABSL_DLL extern const char RFC1123_full[] =
-    "%a, %d %b %E4Y %H:%M:%S %z";
-ABSL_DLL extern const char RFC1123_no_wday[] =
-    "%d %b %E4Y %H:%M:%S %z";
+ABSL_DLL extern const char RFC1123_full[] = "%a, %d %b %E4Y %H:%M:%S %z";
+ABSL_DLL extern const char RFC1123_no_wday[] = "%d %b %E4Y %H:%M:%S %z";
 
 namespace {
 
diff --git a/third_party/abseil-cpp/absl/time/format_benchmark.cc b/third_party/abseil-cpp/absl/time/format_benchmark.cc
index 249c51d..19e481db 100644
--- a/third_party/abseil-cpp/absl/time/format_benchmark.cc
+++ b/third_party/abseil-cpp/absl/time/format_benchmark.cc
@@ -26,7 +26,7 @@
     absl::RFC1123_no_wday,  // 1
     absl::RFC3339_full,     // 2
     absl::RFC3339_sec,      // 3
-    "%Y-%m-%dT%H:%M:%S",    // 4
+    "%Y-%m-%d%ET%H:%M:%S",  // 4
     "%Y-%m-%d",             // 5
 };
 const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/time_zone.h b/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/time_zone.h
index b33e0c0..5562a37 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/time_zone.h
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/time_zone.h
@@ -322,7 +322,8 @@
 // returns the corresponding time_point. Uses strftime()-like formatting
 // options, with the same extensions as cctz::format(), but with the
 // exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez
-// and %E*z also accept the same inputs. %ET accepts either 'T' or 't'.
+// and %E*z also accept the same inputs, which (along with %z) includes
+// 'z' and 'Z' as synonyms for +00:00.  %ET accepts either 'T' or 't'.
 //
 // %Y consumes as many numeric characters as it can, so the matching data
 // should always be terminated with a non-numeric. %E4Y always consumes
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/src/zone_info_source.cc b/third_party/abseil-cpp/absl/time/internal/cctz/src/zone_info_source.cc
index 98ea161..7209533 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/src/zone_info_source.cc
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/src/zone_info_source.cc
@@ -83,7 +83,8 @@
     "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                                   \
     "@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
     "@@ZA")
-#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM64)
+#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM) || \
+    defined(_M_ARM64)
 #pragma comment(                                                                                                          \
     linker,                                                                                                               \
     "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS                     \
diff --git a/third_party/abseil-cpp/absl/time/time.h b/third_party/abseil-cpp/absl/time/time.h
index b456a13..37f6131 100644
--- a/third_party/abseil-cpp/absl/time/time.h
+++ b/third_party/abseil-cpp/absl/time/time.h
@@ -1203,18 +1203,15 @@
 // time with UTC offset.  Also note the use of "%Y": RFC3339 mandates that
 // years have exactly four digits, but we allow them to take their natural
 // width.
-ABSL_DLL extern const char
-    RFC3339_full[];  // %Y-%m-%dT%H:%M:%E*S%Ez
-ABSL_DLL extern const char RFC3339_sec[];  // %Y-%m-%dT%H:%M:%S%Ez
+ABSL_DLL extern const char RFC3339_full[];  // %Y-%m-%d%ET%H:%M:%E*S%Ez
+ABSL_DLL extern const char RFC3339_sec[];   // %Y-%m-%d%ET%H:%M:%S%Ez
 
 // RFC1123_full
 // RFC1123_no_wday
 //
 // FormatTime()/ParseTime() format specifiers for RFC1123 date/time strings.
-ABSL_DLL extern const char
-    RFC1123_full[];  // %a, %d %b %E4Y %H:%M:%S %z
-ABSL_DLL extern const char
-    RFC1123_no_wday[];  // %d %b %E4Y %H:%M:%S %z
+ABSL_DLL extern const char RFC1123_full[];     // %a, %d %b %E4Y %H:%M:%S %z
+ABSL_DLL extern const char RFC1123_no_wday[];  // %d %b %E4Y %H:%M:%S %z
 
 // FormatTime()
 //
@@ -1229,6 +1226,7 @@
 //   - %E#f - Fractional seconds with # digits of precision
 //   - %E*f - Fractional seconds with full precision (a literal '*')
 //   - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
+//   - %ET  - The RFC3339 "date-time" separator "T"
 //
 // Note that %E0S behaves like %S, and %E0f produces no characters.  In
 // contrast %E*f always produces at least one digit, which may be '0'.
@@ -1271,7 +1269,8 @@
 // returns the corresponding `absl::Time`. Uses strftime()-like formatting
 // options, with the same extensions as FormatTime(), but with the
 // exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f.  %Ez
-// and %E*z also accept the same inputs.
+// and %E*z also accept the same inputs, which (along with %z) includes
+// 'z' and 'Z' as synonyms for +00:00.  %ET accepts either 'T' or 't'.
 //
 // %Y consumes as many numeric characters as it can, so the matching data
 // should always be terminated with a non-numeric.  %E4Y always consumes
diff --git a/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_asan_bazel.sh b/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_asan_bazel.sh
index 44794eb5..0c250a6 100755
--- a/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_asan_bazel.sh
+++ b/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_asan_bazel.sh
@@ -78,7 +78,6 @@
         /usr/local/bin/bazel test ... \
           --compilation_mode="${compilation_mode}" \
           --copt="${exceptions_mode}" \
-          --copt="-DDYNAMIC_ANNOTATIONS_ENABLED=1" \
           --copt="-DADDRESS_SANITIZER" \
           --copt="-DUNDEFINED_BEHAVIOR_SANITIZER" \
           --copt="-fsanitize=address" \
diff --git a/third_party/android_deps/BUILD.gn b/third_party/android_deps/BUILD.gn
index b87d2cb..6caac69 100644
--- a/third_party/android_deps/BUILD.gn
+++ b/third_party/android_deps/BUILD.gn
@@ -1393,7 +1393,7 @@
 # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
 java_prebuilt("com_google_protobuf_protobuf_javalite_java") {
   jar_path =
-      "libs/com_google_protobuf_protobuf_javalite/protobuf-javalite-3.11.4.jar"
+      "libs/com_google_protobuf_protobuf_javalite/protobuf-javalite-3.12.2.jar"
   output_name = "com_google_protobuf_protobuf_javalite"
   supports_android = true
 }
diff --git a/third_party/android_deps/build.gradle b/third_party/android_deps/build.gradle
index 1aa09764..65fd7f38 100644
--- a/third_party/android_deps/build.gradle
+++ b/third_party/android_deps/build.gradle
@@ -123,7 +123,7 @@
     compile "com.google.guava:failureaccess:1.0.1"
     compile "com.google.guava:listenablefuture:1.0"
     compile "com.google.j2objc:j2objc-annotations:1.1"
-    compile "com.google.protobuf:protobuf-javalite:3.11.4"
+    compile "com.google.protobuf:protobuf-javalite:3.12.2"
     compile "javax.annotation:javax.annotation-api:1.3.2"
     compile "javax.annotation:jsr250-api:1.0"
     compile "javax.inject:javax.inject:1"
diff --git a/third_party/android_deps/fetch_all.py b/third_party/android_deps/fetch_all.py
index 2ee4de98..117ebae 100755
--- a/third_party/android_deps/fetch_all.py
+++ b/third_party/android_deps/fetch_all.py
@@ -305,6 +305,11 @@
         for info, result in executor.map(cipd_describe, cipd_pkg_infos):
             if result:
                 pkg_path, pkg_name, pkg_tag = info
+                # pkg_path is implicitly relative to _CHROMIUM_SRC, make it
+                # explicit.
+                pkg_path = os.path.join(_CHROMIUM_SRC, pkg_path)
+                # Now make pkg_path relative to os.curdir.
+                pkg_path = os.path.relpath(pkg_path)
                 cmds.append(TEMPLATE.format(pkg_path, pkg_name, pkg_tag))
     return cmds
 
diff --git a/third_party/android_deps/libs/com_google_protobuf_protobuf_javalite/README.chromium b/third_party/android_deps/libs/com_google_protobuf_protobuf_javalite/README.chromium
index 7c4ea863..fb85598b 100644
--- a/third_party/android_deps/libs/com_google_protobuf_protobuf_javalite/README.chromium
+++ b/third_party/android_deps/libs/com_google_protobuf_protobuf_javalite/README.chromium
@@ -1,7 +1,7 @@
 Name: Protocol Buffers [Lite]
 Short Name: protobuf-javalite
 URL: https://github.com/protocolbuffers/protobuf/blob/master/java/lite.md
-Version: 3.11.4
+Version: 3.12.2
 License: BSD
 License File: LICENSE
 Security Critical: yes
diff --git a/third_party/android_deps/libs/com_google_protobuf_protobuf_javalite/cipd.yaml b/third_party/android_deps/libs/com_google_protobuf_protobuf_javalite/cipd.yaml
index 9d02df9b..decdf73 100644
--- a/third_party/android_deps/libs/com_google_protobuf_protobuf_javalite/cipd.yaml
+++ b/third_party/android_deps/libs/com_google_protobuf_protobuf_javalite/cipd.yaml
@@ -3,8 +3,8 @@
 # found in the LICENSE file.
 
 # To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml -tag version:3.11.4-cr0
+# cipd create --pkg-def cipd.yaml -tag version:3.12.2-cr0
 package: chromium/third_party/android_deps/libs/com_google_protobuf_protobuf_javalite
 description: "Protocol Buffers [Lite]"
 data:
-- file: protobuf-javalite-3.11.4.jar
+- file: protobuf-javalite-3.12.2.jar
diff --git a/third_party/android_protoc/README.chromium b/third_party/android_protoc/README.chromium
index e3de1a0..0aed971b8 100644
--- a/third_party/android_protoc/README.chromium
+++ b/third_party/android_protoc/README.chromium
@@ -1,7 +1,7 @@
 Name: Protocol Buffers - Google's data interchange format
 Short Name: protobuf
-URL: https://github.com/protocolbuffers/protobuf/releases/download/v3.11.4/protoc-3.11.4-linux-x86_64.zip
-Version: 3.11.4
+URL: https://github.com/protocolbuffers/protobuf/releases/download/v3.12.2/protoc-3.12.2-linux-x86_64.zip
+Version: 3.12.2
 License: BSD
 License File: NOT_SHIPPED
 Security Critical: no
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 60476ff..5fc52354 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -278,7 +278,7 @@
     "AudioWorkletRealtimeThread", base::FEATURE_DISABLED_BY_DEFAULT};
 
 // A feature to reduce the set of resources fetched by No-State Prefetch.
-const base::Feature kLightweightNoStatePrefetch{
+const base::Feature kLightweightNoStatePrefetch {
   "LightweightNoStatePrefetch",
 #if defined(OS_ANDROID)
       base::FEATURE_ENABLED_BY_DEFAULT
@@ -287,10 +287,6 @@
 #endif
 };
 
-// A feature to enable web fonts to be fetched by No-State Prefetch.
-const base::Feature kLightweightNoStatePrefetch_FetchFonts{
-    "LightweightNoStatePrefetch_FetchFonts", base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Automatically convert light-themed pages to use a Blink-generated dark theme
 const base::Feature kForceWebContentsDarkMode{
     "WebContentsForceDark", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index a593f56..ae28b75 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -82,8 +82,6 @@
 BLINK_COMMON_EXPORT extern const base::Feature kAudioWorkletRealtimeThread;
 
 BLINK_COMMON_EXPORT extern const base::Feature kLightweightNoStatePrefetch;
-BLINK_COMMON_EXPORT extern const base::Feature
-    kLightweightNoStatePrefetch_FetchFonts;
 
 BLINK_COMMON_EXPORT extern const base::Feature kSaveDataImgSrcset;
 
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn
index d26b93c..92e0e02 100644
--- a/third_party/blink/public/mojom/BUILD.gn
+++ b/third_party/blink/public/mojom/BUILD.gn
@@ -45,6 +45,7 @@
     "devtools/devtools_agent.mojom",
     "devtools/devtools_frontend.mojom",
     "devtools/inspector_issue.mojom",
+    "digital_goods/digital_goods.mojom",
     "disk_allocator.mojom",
     "favicon/favicon_url.mojom",
     "feature_observer/feature_observer.mojom",
diff --git a/third_party/blink/public/mojom/digital_goods/OWNERS b/third_party/blink/public/mojom/digital_goods/OWNERS
new file mode 100644
index 0000000..bf8fcba
--- /dev/null
+++ b/third_party/blink/public/mojom/digital_goods/OWNERS
@@ -0,0 +1,6 @@
+file://third_party/blink/renderer/modules/payments/goods/OWNERS
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+# COMPONENT: UI>Browser>WebAppInstalls>ChromeOS
diff --git a/third_party/blink/public/mojom/digital_goods/digital_goods.mojom b/third_party/blink/public/mojom/digital_goods/digital_goods.mojom
new file mode 100644
index 0000000..ef162ac
--- /dev/null
+++ b/third_party/blink/public/mojom/digital_goods/digital_goods.mojom
@@ -0,0 +1,50 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module payments.mojom;
+
+import "components/payments/mojom/payment_request_data.mojom";
+
+// https://github.com/WICG/digital-goods/blob/master/explainer.md
+
+struct GetDetailsParams {
+  array<string> item_ids;
+};
+
+struct GetDetailsResponse {
+  BillingResponseCode code;
+  array<ItemDetails> item_details_list;
+};
+
+struct ConsumeParams {
+  string purchase_token;
+  bool make_available_again;
+};
+
+struct ConsumeResponse {
+  BillingResponseCode code;
+};
+
+// TODO(crbug.com/1061503): Narrow down this list as discussions settle on
+// https://github.com/WICG/digital-goods/blob/master/explainer.md
+enum BillingResponseCode {
+  kOk,
+  kError,
+  kBillingUnavailable,
+  kDeveloperError,
+  kFeatureNotSupported,
+  kItemAlreadyOwned,
+  kItemNotOwned,
+  kItemUnavailable,
+  kServiceDisconnected,
+  kServiceUnavailable,
+  kUserCancelled,
+};
+
+struct ItemDetails {
+  string item_id;
+  string title;
+  string description;
+  PaymentCurrencyAmount price;
+};
diff --git a/third_party/blink/public/mojom/frame/find_in_page.mojom b/third_party/blink/public/mojom/frame/find_in_page.mojom
index 553126c..5d0114a8 100644
--- a/third_party/blink/public/mojom/frame/find_in_page.mojom
+++ b/third_party/blink/public/mojom/frame/find_in_page.mojom
@@ -7,9 +7,9 @@
 import "ui/gfx/geometry/mojom/geometry.mojom";
 
 interface FindInPage {
-  // If |options.find_next| is false, this is a "Start Find" call.
+  // If |options.new_session| is true, this is a "Start Find" call.
   // It starts a new find-in-page session with id |request_id|.
-  // If |options.find_next| is true, this is a "Find Next" call.
+  // If |options.new_session| is false, this is a "Find Next" call.
   // It asks the active/highlighted match for session with id |request_id|
   // to be moved either forward if |options.forward| is true, or backwards
   // if |options.forward| is false.
@@ -106,12 +106,17 @@
   bool match_case = false;
 
   // Whether this operation is the first request or a follow-up.
-  bool find_next = false;
+  bool new_session = true;
 
   // Force a re-search of the frame: typically used when forcing a re-search
   // after the frame navigates.
   bool force = false;
 
+  // Whether to keep searching if the result is an exact match of the selection.
+  // This should generally be set to true unless you're starting a new find
+  // based on the selection.
+  bool find_next_if_selection_matches = true;
+
   // Signifies whether we should force text scoping to happen immediately
   // or not. Only used for testing purposes.
   bool run_synchronously_for_testing = false;
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h
index e0aa20f..8c28b69 100644
--- a/third_party/blink/public/platform/web_runtime_features.h
+++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -186,10 +186,10 @@
   BLINK_PLATFORM_EXPORT static void EnableWebXR(bool);
   BLINK_PLATFORM_EXPORT static void EnableWebXRAnchors(bool);
   BLINK_PLATFORM_EXPORT static void EnableWebXRARModule(bool);
-  BLINK_PLATFORM_EXPORT static void EnableWebXRHitTest(bool);
-  BLINK_PLATFORM_EXPORT static void EnableWebXRIncubations(bool);
-  BLINK_PLATFORM_EXPORT static void EnableWebXRLightEstimation(bool);
   BLINK_PLATFORM_EXPORT static void EnableWebXRCameraAccess(bool);
+  BLINK_PLATFORM_EXPORT static void EnableWebXRHitTest(bool);
+  BLINK_PLATFORM_EXPORT static void EnableWebXRLightEstimation(bool);
+  BLINK_PLATFORM_EXPORT static void EnableWebXRPlaneDetection(bool);
   BLINK_PLATFORM_EXPORT static void EnableXSLT(bool);
   BLINK_PLATFORM_EXPORT static void ForceOverlayFullscreenVideo(bool);
   BLINK_PLATFORM_EXPORT static void EnableTimerThrottlingForBackgroundTabs(
diff --git a/third_party/blink/public/web/DEPS b/third_party/blink/public/web/DEPS
index 3ba6b11d..8a07fcf 100644
--- a/third_party/blink/public/web/DEPS
+++ b/third_party/blink/public/web/DEPS
@@ -37,6 +37,7 @@
     "+services/network/public/mojom/ip_address_space.mojom-shared.h",
     "+services/network/public/mojom/referrer_policy.mojom-shared.h",
     "+services/network/public/mojom/url_loader.mojom-shared.h",
+    "+services/network/public/mojom/url_loader_factory.mojom-shared.h",
     "+services/service_manager/public",
     "+ui/base/ime/ime_text_span.h",
     "+ui/events/types",
diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
index cedb7e23..48e3e7ec 100644
--- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
+++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
@@ -35,9 +35,9 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "base/time/time.h"
-#include "mojo/public/cpp/system/message_pipe.h"
 #include "services/network/public/mojom/url_loader.mojom-shared.h"
 #include "third_party/blink/public/mojom/devtools/console_message.mojom-shared.h"
+#include "third_party/blink/public/mojom/devtools/devtools_agent.mojom-shared.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom-shared.h"
 #include "third_party/blink/public/mojom/web_feature/web_feature.mojom-shared.h"
 #include "third_party/blink/public/platform/cross_variant_mojo_util.h"
@@ -79,8 +79,10 @@
   // ServiceWorker has prepared everything for script loading and is now ready
   // for DevTools inspection. Called on the initiator thread.
   virtual void WorkerReadyForInspectionOnInitiatorThread(
-      mojo::ScopedMessagePipeHandle devtools_agent_ptr_info,
-      mojo::ScopedMessagePipeHandle devtools_agent_host_request) {}
+      CrossVariantMojoRemote<mojom::DevToolsAgentInterfaceBase>
+          devtools_agent_remote,
+      CrossVariantMojoReceiver<mojom::DevToolsAgentHostInterfaceBase>
+          devtools_agent_host_receiver) {}
 
   // The worker started but it could not execute because fetching the classic
   // script failed on the worker thread.
diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
index 225b416..c9ef9df 100644
--- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
+++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
@@ -33,7 +33,9 @@
 
 #include "base/time/time.h"
 #include "mojo/public/cpp/system/data_pipe.h"
-#include "mojo/public/cpp/system/message_pipe.h"
+#include "third_party/blink/public/mojom/service_worker/controller_service_worker.mojom-shared.h"
+#include "third_party/blink/public/mojom/service_worker/service_worker.mojom-shared.h"
+#include "third_party/blink/public/platform/cross_variant_mojo_util.h"
 
 #include <memory>
 
@@ -49,11 +51,10 @@
   virtual ~WebServiceWorkerContextProxy() = default;
 
   virtual void BindServiceWorker(
-      // A handle for mojo::PendingReceiver<mojom::ServiceWorker>.
-      mojo::ScopedMessagePipeHandle receiver_pipe) = 0;
+      CrossVariantMojoReceiver<mojom::ServiceWorkerInterfaceBase> receiver) = 0;
   virtual void BindControllerServiceWorker(
-      // A handle for mojo::PendingReceiver<mojom::ControllerServiceWorker>.
-      mojo::ScopedMessagePipeHandle receiver_pipe) = 0;
+      CrossVariantMojoReceiver<mojom::ControllerServiceWorkerInterfaceBase>
+          receiver) = 0;
 
   virtual void OnNavigationPreloadResponse(
       int fetch_event_id,
diff --git a/third_party/blink/public/web/web_local_frame.h b/third_party/blink/public/web/web_local_frame.h
index 6e0ac49..bdb7ff0 100644
--- a/third_party/blink/public/web/web_local_frame.h
+++ b/third_party/blink/public/web/web_local_frame.h
@@ -560,7 +560,7 @@
                               const WebString& search_text,
                               bool match_case,
                               bool forward,
-                              bool find_next,
+                              bool new_session,
                               bool force,
                               bool wrap_within_frame) = 0;
 
diff --git a/third_party/blink/public/web/web_navigation_params.h b/third_party/blink/public/web/web_navigation_params.h
index 9ba0ec5..e2faca5 100644
--- a/third_party/blink/public/web/web_navigation_params.h
+++ b/third_party/blink/public/web/web_navigation_params.h
@@ -11,9 +11,9 @@
 #include "base/optional.h"
 #include "base/time/time.h"
 #include "base/unguessable_token.h"
-#include "mojo/public/cpp/system/message_pipe.h"
 #include "services/network/public/mojom/ip_address_space.mojom-shared.h"
 #include "services/network/public/mojom/referrer_policy.mojom-shared.h"
+#include "services/network/public/mojom/url_loader_factory.mojom-shared.h"
 #include "third_party/blink/public/common/frame/frame_policy.h"
 #include "third_party/blink/public/common/navigation/triggering_event_info.h"
 #include "third_party/blink/public/mojom/blob/blob_url_store.mojom-shared.h"
@@ -353,14 +353,16 @@
         const WebString& header_integrity,
         const WebURL& inner_url,
         const WebURLResponse& inner_response,
-        mojo::ScopedMessagePipeHandle loader_factory_handle);
+        CrossVariantMojoRemote<network::mojom::URLLoaderFactoryInterfaceBase>
+            loader_factory);
     ~PrefetchedSignedExchange();
 
     WebURL outer_url;
     WebString header_integrity;
     WebURL inner_url;
     WebURLResponse inner_response;
-    mojo::ScopedMessagePipeHandle loader_factory_handle;
+    CrossVariantMojoRemote<network::mojom::URLLoaderFactoryInterfaceBase>
+        loader_factory;
   };
   WebVector<std::unique_ptr<PrefetchedSignedExchange>>
       prefetched_signed_exchanges;
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_expr.py b/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_expr.py
index f3ae80f0..fe953c4 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_expr.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_expr.py
@@ -270,6 +270,16 @@
         feature_selector_names.extend(
             exposure.context_dependent_runtime_enabled_features)
 
+    # [ContextEnabled]
+    if exposure.context_enabled_features:
+        terms = map(
+            lambda feature: _Expr(
+                "${{context_feature_settings}}->is{}Enabled()".format(
+                    feature)), exposure.context_enabled_features)
+        feature_enabled_terms.append(
+            expr_and([_Expr("${context_feature_settings}"),
+                      expr_or(terms)]))
+
     # Build an expression.
     top_level_terms = []
     top_level_terms.append(secure_context_term)
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py b/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py
index 8186f572..ec7dba17 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py
@@ -52,6 +52,7 @@
             blink_name = (member.code_generator_info.property_implemented_as
                           or member.identifier)
             self.get_api = name_style.api_func(blink_name)
+            self.get_or_api = name_style.api_func(blink_name, "or")
             self.set_api = name_style.api_func("set", blink_name)
             self.has_api = name_style.api_func("has", blink_name)
             # C++ data member that shows the presence of the IDL member.
@@ -290,15 +291,16 @@
     blink_member_name = _blink_member_name(member)
     name = blink_member_name.get_api
     blink_type = blink_type_info(member.idl_type)
+    const_ref_t = blink_type.const_ref_t
+    ref_t = blink_type.ref_t
 
     decls = ListNode()
     defs = ListNode()
 
-    func_def = CxxFuncDefNode(
-        name=name,
-        arg_decls=[],
-        return_type=blink_type.const_ref_t,
-        const=True)
+    func_def = CxxFuncDefNode(name=name,
+                              arg_decls=[],
+                              return_type=const_ref_t,
+                              const=True)
     decls.append(func_def)
     func_def.set_base_template_vars(cg_context.template_bindings())
     func_def.body.extend([
@@ -306,9 +308,8 @@
         TextNode(_format("return {};", blink_member_name.value_var)),
     ])
 
-    if blink_type.ref_t != blink_type.const_ref_t:
-        func_def = CxxFuncDefNode(
-            name=name, arg_decls=[], return_type=blink_type.ref_t)
+    if ref_t != const_ref_t:
+        func_def = CxxFuncDefNode(name=name, arg_decls=[], return_type=ref_t)
         decls.append(func_def)
         func_def.set_base_template_vars(cg_context.template_bindings())
         func_def.body.extend([
@@ -316,6 +317,24 @@
             TextNode(_format("return {};", blink_member_name.value_var)),
         ])
 
+    if not _is_member_always_present(member):
+        func_def = CxxFuncDefNode(
+            name=blink_member_name.get_or_api,
+            arg_decls=[_format("{} fallback_value", blink_type.value_t)],
+            return_type=blink_type.value_t,
+            const=True)
+        decls.append(func_def)
+        func_def.set_base_template_vars(cg_context.template_bindings())
+        body_node = TextNode(
+            _format("""\
+if ({has}()) {{
+  return {get}();
+}}
+return std::move(fallback_value);""",
+                    has=blink_member_name.has_api,
+                    get=blink_member_name.get_api))
+        func_def.body.append(body_node)
+
     return decls, defs
 
 
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
index df81c7c..29bc30d 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -4013,6 +4013,19 @@
            "${class_name}::GetWrapperTypeInfo();")),
     ])
 
+    # context_feature_settings
+    node = S("context_feature_settings",
+             ("const ContextFeatureSettings* ${context_feature_settings} = "
+              "ContextFeatureSettings::From("
+              "${execution_context}, "
+              "ContextFeatureSettings::CreationMode::kDontCreateIfNotExists"
+              ");"))
+    node.accumulate(
+        CodeGenAccumulator.require_include_headers([
+            "third_party/blink/renderer/core/context_features/context_feature_settings.h"
+        ]))
+    local_vars.append(node)
+
     # execution_context
     node = S("execution_context", ("ExecutionContext* ${execution_context} = "
                                    "ExecutionContext::From(${script_state});"))
@@ -6060,15 +6073,6 @@
     api_class_def.set_base_template_vars(cg_context.template_bindings())
     api_class_def.bottom_section.append(
         TextNode("friend class {};".format(blink_class_name(interface))))
-    api_base_class_def = CxxNamespaceNode(
-        name="bindings",
-        body=TextNode(
-            _format(
-                "template class {export} "
-                "V8InterfaceBridge<{class_name}, {blink_impl_class}>;",
-                export=component_export(api_component),
-                class_name=cg_context.class_name,
-                blink_impl_class=blink_class_name(interface))))
     if is_cross_components:
         impl_class_def = CxxClassDefNode(
             impl_class_name,
@@ -6419,8 +6423,6 @@
     api_header_blink_ns.body.extend([
         api_class_def,
         EmptyNode(),
-        api_base_class_def,
-        EmptyNode(),
     ])
     if is_cross_components:
         impl_header_blink_ns.body.append(impl_class_def)
diff --git a/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py b/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py
index f01214a..2c6dc43d 100755
--- a/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py
+++ b/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py
@@ -40,7 +40,6 @@
     'Vector<GridTrackSize>',
     'Vector<AtomicString>',
     'GridPosition',
-    'GapLength',
     'AtomicString',
     'scoped_refptr',
     'Persistent',
@@ -52,6 +51,7 @@
     'IntrinsicLength',
     'TextDecorationThickness',
     # Aligns like float
+    'base::Optional<Length>',
     'StyleOffsetRotation',
     'TransformOrigin',
     'ScrollPadding',
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 07f9659..6633f12 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1337,7 +1337,6 @@
     "page/validation_message_overlay_delegate_test.cc",
     "page/viewport_test.cc",
     "page/window_features_test.cc",
-    "page/zoom_test.cc",
     "paint/block_painter_test.cc",
     "paint/box_paint_invalidator_test.cc",
     "paint/box_painter_test.cc",
diff --git a/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc b/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
index f21aa67b..a5d107d 100644
--- a/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
+++ b/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
@@ -60,7 +60,7 @@
     const PropertyRegistry* registry,
     const Document& document)
     : registry_(registry) {
-  allow_all_animations_ = document.IsFeatureEnabled(
+  allow_all_animations_ = document.GetExecutionContext()->IsFeatureEnabled(
       blink::mojom::blink::DocumentPolicyFeature::kLayoutAnimations);
 }
 
diff --git a/third_party/blink/renderer/core/animation/length_property_functions.cc b/third_party/blink/renderer/core/animation/length_property_functions.cc
index 4e26d39..04f82bd 100644
--- a/third_party/blink/renderer/core/animation/length_property_functions.cc
+++ b/third_party/blink/renderer/core/animation/length_property_functions.cc
@@ -256,14 +256,14 @@
       result = Length::Fixed(style.VerticalBorderSpacing());
       return true;
     case CSSPropertyID::kRowGap:
-      if (style.RowGap().IsNormal())
+      if (!style.RowGap())
         return false;
-      result = style.RowGap().GetLength();
+      result = *style.RowGap();
       return true;
     case CSSPropertyID::kColumnGap:
-      if (style.ColumnGap().IsNormal())
+      if (!style.ColumnGap())
         return false;
-      result = style.ColumnGap().GetLength();
+      result = *style.ColumnGap();
       return true;
     case CSSPropertyID::kColumnRuleWidth:
       result = Length::Fixed(style.ColumnRuleWidth());
diff --git a/third_party/blink/renderer/core/css/BUILD.gn b/third_party/blink/renderer/core/css/BUILD.gn
index aae8165..34da2de 100644
--- a/third_party/blink/renderer/core/css/BUILD.gn
+++ b/third_party/blink/renderer/core/css/BUILD.gn
@@ -413,8 +413,6 @@
     "parser/css_parser_token_stream.h",
     "parser/css_property_parser.cc",
     "parser/css_property_parser.h",
-    "parser/css_property_parser_helpers.cc",
-    "parser/css_property_parser_helpers.h",
     "parser/css_selector_parser.cc",
     "parser/css_selector_parser.h",
     "parser/css_supports_parser.cc",
@@ -651,7 +649,6 @@
     "parser/css_parser_local_context_test.cc",
     "parser/css_parser_token_stream_test.cc",
     "parser/css_parser_token_test.cc",
-    "parser/css_property_parser_helpers_test.cc",
     "parser/css_property_parser_test.cc",
     "parser/css_selector_parser_test.cc",
     "parser/css_supports_parser_test.cc",
diff --git a/third_party/blink/renderer/core/css/css_math_expression_node.cc b/third_party/blink/renderer/core/css/css_math_expression_node.cc
index 7085288..e74f5b73 100644
--- a/third_party/blink/renderer/core/css/css_math_expression_node.cc
+++ b/third_party/blink/renderer/core/css/css_math_expression_node.cc
@@ -32,7 +32,7 @@
 
 #include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
 #include "third_party/blink/renderer/core/css/css_primitive_value_mappings.h"
-#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
 #include "third_party/blink/renderer/platform/geometry/calculation_expression_node.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
@@ -1029,7 +1029,7 @@
       last_token_is_comma = false;
       operands.push_back(operand);
 
-      if (!css_property_parser_helpers::ConsumeCommaIncludingWhitespace(tokens))
+      if (!css_parsing_utils::ConsumeCommaIncludingWhitespace(tokens))
         break;
       last_token_is_comma = true;
     }
@@ -1048,14 +1048,14 @@
     if (!min_operand)
       return nullptr;
 
-    if (!css_property_parser_helpers::ConsumeCommaIncludingWhitespace(tokens))
+    if (!css_parsing_utils::ConsumeCommaIncludingWhitespace(tokens))
       return nullptr;
 
     CSSMathExpressionNode* val_operand = ParseValueExpression(tokens, depth);
     if (!val_operand)
       return nullptr;
 
-    if (!css_property_parser_helpers::ConsumeCommaIncludingWhitespace(tokens))
+    if (!css_parsing_utils::ConsumeCommaIncludingWhitespace(tokens))
       return nullptr;
 
     CSSMathExpressionNode* max_operand = ParseValueExpression(tokens, depth);
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index ed5c4c2..9a5587d 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -4076,9 +4076,9 @@
       interpolable: true,
       field_group: "*",
       field_template: "external",
-      include_paths: ["third_party/blink/renderer/core/style/gap_length.h"],
-      default_value: "GapLength()",
-      type_name: "GapLength",
+      include_paths: ["third_party/blink/renderer/platform/geometry/length.h"],
+      default_value: "base::nullopt",
+      type_name: "base::Optional<Length>",
       converter: "ConvertGapLength",
       keywords: ["normal"],
       typedom_types: ["Keyword", "Length", "Percentage"],
@@ -4089,9 +4089,9 @@
       interpolable: true,
       field_group: "*",
       field_template: "external",
-      include_paths: ["third_party/blink/renderer/core/style/gap_length.h"],
-      default_value: "GapLength()",
-      type_name: "GapLength",
+      include_paths: ["third_party/blink/renderer/platform/geometry/length.h"],
+      default_value: "base::nullopt",
+      type_name: "base::Optional<Length>",
       converter: "ConvertGapLength",
       keywords: ["normal"],
       typedom_types: ["Keyword", "Length", "Percentage"],
diff --git a/third_party/blink/renderer/core/css/css_syntax_definition.cc b/third_party/blink/renderer/core/css/css_syntax_definition.cc
index a3dc48a5..9a09c65e 100644
--- a/third_party/blink/renderer/core/css/css_syntax_definition.cc
+++ b/third_party/blink/renderer/core/css/css_syntax_definition.cc
@@ -11,8 +11,8 @@
 #include "third_party/blink/renderer/core/css/css_value_list.h"
 #include "third_party/blink/renderer/core/css/css_variable_reference_value.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_idioms.h"
-#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
 #include "third_party/blink/renderer/core/css/parser/css_variable_parser.h"
+#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
 #include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
@@ -29,8 +29,8 @@
 bool IsReservedIdentToken(const CSSParserToken& token) {
   if (token.GetType() != kIdentToken)
     return false;
-  return css_property_parser_helpers::IsRevertKeyword(token.Value()) ||
-         css_property_parser_helpers::IsDefaultKeyword(token.Value());
+  return css_parsing_utils::IsRevertKeyword(token.Value()) ||
+         css_parsing_utils::IsDefaultKeyword(token.Value());
 }
 
 bool CouldConsumeReservedKeyword(CSSParserTokenRange range) {
@@ -55,51 +55,50 @@
     case CSSSyntaxType::kLength: {
       CSSParserContext::ParserModeOverridingScope scope(context,
                                                         kHTMLStandardMode);
-      return css_property_parser_helpers::ConsumeLength(
-          range, context, ValueRange::kValueRangeAll);
+      return css_parsing_utils::ConsumeLength(range, context,
+                                              ValueRange::kValueRangeAll);
     }
     case CSSSyntaxType::kNumber:
-      return css_property_parser_helpers::ConsumeNumber(
-          range, context, ValueRange::kValueRangeAll);
+      return css_parsing_utils::ConsumeNumber(range, context,
+                                              ValueRange::kValueRangeAll);
     case CSSSyntaxType::kPercentage:
-      return css_property_parser_helpers::ConsumePercent(
-          range, context, ValueRange::kValueRangeAll);
+      return css_parsing_utils::ConsumePercent(range, context,
+                                               ValueRange::kValueRangeAll);
     case CSSSyntaxType::kLengthPercentage: {
       CSSParserContext::ParserModeOverridingScope scope(context,
                                                         kHTMLStandardMode);
-      return css_property_parser_helpers::ConsumeLengthOrPercent(
+      return css_parsing_utils::ConsumeLengthOrPercent(
           range, context, ValueRange::kValueRangeAll);
     }
     case CSSSyntaxType::kColor: {
       CSSParserContext::ParserModeOverridingScope scope(context,
                                                         kHTMLStandardMode);
-      return css_property_parser_helpers::ConsumeColor(range, context);
+      return css_parsing_utils::ConsumeColor(range, context);
     }
     case CSSSyntaxType::kImage:
-      return css_property_parser_helpers::ConsumeImage(range, context);
+      return css_parsing_utils::ConsumeImage(range, context);
     case CSSSyntaxType::kUrl:
-      return css_property_parser_helpers::ConsumeUrl(range, context);
+      return css_parsing_utils::ConsumeUrl(range, context);
     case CSSSyntaxType::kInteger:
-      return css_property_parser_helpers::ConsumeIntegerOrNumberCalc(range,
-                                                                     context);
+      return css_parsing_utils::ConsumeIntegerOrNumberCalc(range, context);
     case CSSSyntaxType::kAngle:
-      return css_property_parser_helpers::ConsumeAngle(
-          range, context, base::Optional<WebFeature>());
+      return css_parsing_utils::ConsumeAngle(range, context,
+                                             base::Optional<WebFeature>());
     case CSSSyntaxType::kTime:
-      return css_property_parser_helpers::ConsumeTime(
-          range, context, ValueRange::kValueRangeAll);
+      return css_parsing_utils::ConsumeTime(range, context,
+                                            ValueRange::kValueRangeAll);
     case CSSSyntaxType::kResolution:
-      return css_property_parser_helpers::ConsumeResolution(range);
+      return css_parsing_utils::ConsumeResolution(range);
     case CSSSyntaxType::kTransformFunction:
-      return css_property_parser_helpers::ConsumeTransformValue(range, context);
+      return css_parsing_utils::ConsumeTransformValue(range, context);
     case CSSSyntaxType::kTransformList:
-      return css_property_parser_helpers::ConsumeTransformList(range, context);
+      return css_parsing_utils::ConsumeTransformList(range, context);
     case CSSSyntaxType::kCustomIdent:
       // TODO(crbug.com/579788): Implement 'revert'.
       // TODO(crbug.com/882285): Make 'default' invalid as <custom-ident>.
       if (IsReservedIdentToken(range.Peek()))
         return nullptr;
-      return css_property_parser_helpers::ConsumeCustomIdent(range, context);
+      return css_parsing_utils::ConsumeCustomIdent(range, context);
     default:
       NOTREACHED();
       return nullptr;
@@ -127,8 +126,7 @@
       if (!value)
         return nullptr;
       list->Append(*value);
-    } while (
-        css_property_parser_helpers::ConsumeCommaIncludingWhitespace(range));
+    } while (css_parsing_utils::ConsumeCommaIncludingWhitespace(range));
     return list->length() ? list : nullptr;
   }
   const CSSValue* result = ConsumeSingleType(syntax, range, context);
diff --git a/third_party/blink/renderer/core/css/css_syntax_string_parser.cc b/third_party/blink/renderer/core/css/css_syntax_string_parser.cc
index a045ab4..de743ba 100644
--- a/third_party/blink/renderer/core/css/css_syntax_string_parser.cc
+++ b/third_party/blink/renderer/core/css/css_syntax_string_parser.cc
@@ -7,7 +7,7 @@
 #include <utility>
 #include "third_party/blink/renderer/core/css/css_syntax_component.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_idioms.h"
-#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
 #include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
@@ -151,9 +151,9 @@
 bool CSSSyntaxStringParser::ConsumeIdent(String& ident) {
   ident = ConsumeName(input_);
   // TODO(crbug.com/882285): Make 'default' invalid as <custom-ident>.
-  return !css_property_parser_helpers::IsCSSWideKeyword(ident) &&
-         !css_property_parser_helpers::IsRevertKeyword(ident) &&
-         !css_property_parser_helpers::IsDefaultKeyword(ident);
+  return !css_parsing_utils::IsCSSWideKeyword(ident) &&
+         !css_parsing_utils::IsRevertKeyword(ident) &&
+         !css_parsing_utils::IsDefaultKeyword(ident);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/font_face_set_document.cc b/third_party/blink/renderer/core/css/font_face_set_document.cc
index 816cf73..7e9604a 100644
--- a/third_party/blink/renderer/core/css/font_face_set_document.cc
+++ b/third_party/blink/renderer/core/css/font_face_set_document.cc
@@ -35,7 +35,7 @@
 #include "third_party/blink/renderer/core/css/font_face_cache.h"
 #include "third_party/blink/renderer/core/css/font_face_set_load_event.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser.h"
-#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
 #include "third_party/blink/renderer/core/css/resolver/font_style_resolver.h"
 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
 #include "third_party/blink/renderer/core/css/style_engine.h"
@@ -174,7 +174,7 @@
     return false;
 
   String font_value = parsed_style->GetPropertyValue(CSSPropertyID::kFont);
-  if (css_property_parser_helpers::IsCSSWideKeyword(font_value))
+  if (css_parsing_utils::IsCSSWideKeyword(font_value))
     return false;
 
   if (!GetDocument()->documentElement()) {
diff --git a/third_party/blink/renderer/core/css/font_face_set_worker.cc b/third_party/blink/renderer/core/css/font_face_set_worker.cc
index 6c8ba0384..2a12d3b 100644
--- a/third_party/blink/renderer/core/css/font_face_set_worker.cc
+++ b/third_party/blink/renderer/core/css/font_face_set_worker.cc
@@ -12,7 +12,7 @@
 #include "third_party/blink/renderer/core/css/font_face_set_load_event.h"
 #include "third_party/blink/renderer/core/css/offscreen_font_selector.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser.h"
-#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
 #include "third_party/blink/renderer/core/css/resolver/font_style_resolver.h"
 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -84,7 +84,7 @@
     return false;
 
   String font_value = parsed_style->GetPropertyValue(CSSPropertyID::kFont);
-  if (css_property_parser_helpers::IsCSSWideKeyword(font_value))
+  if (css_parsing_utils::IsCSSWideKeyword(font_value))
     return false;
 
   FontFamily font_family;
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 c1778ce3..5cdd457c 100644
--- a/third_party/blink/renderer/core/css/media_query_exp.cc
+++ b/third_party/blink/renderer/core/css/media_query_exp.cc
@@ -34,7 +34,7 @@
 #include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
-#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
 #include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/decimal.h"
@@ -281,22 +281,21 @@
   CSSParserContext::ParserModeOverridingScope scope(context, kHTMLStandardMode);
 
   CSSPrimitiveValue* value =
-      css_property_parser_helpers::ConsumeInteger(range, context, 0);
+      css_parsing_utils::ConsumeInteger(range, context, 0);
   if (!value && !FeatureExpectingPositiveInteger(lower_media_feature) &&
       !FeatureWithAspectRatio(lower_media_feature)) {
-    value = css_property_parser_helpers::ConsumeNumber(range, context,
-                                                       kValueRangeNonNegative);
+    value = css_parsing_utils::ConsumeNumber(range, context,
+                                             kValueRangeNonNegative);
   }
   if (!value) {
-    value = css_property_parser_helpers::ConsumeLength(range, context,
-                                                       kValueRangeNonNegative);
+    value = css_parsing_utils::ConsumeLength(range, context,
+                                             kValueRangeNonNegative);
   }
   if (!value)
-    value = css_property_parser_helpers::ConsumeResolution(range);
+    value = css_parsing_utils::ConsumeResolution(range);
 
   if (!value) {
-    if (CSSIdentifierValue* ident =
-            css_property_parser_helpers::ConsumeIdent(range)) {
+    if (CSSIdentifierValue* ident = css_parsing_utils::ConsumeIdent(range)) {
       CSSValueID ident_id = ident->GetValueID();
       if (!FeatureWithValidIdent(lower_media_feature, ident_id))
         return Invalid();
@@ -316,10 +315,10 @@
   if (FeatureWithAspectRatio(lower_media_feature)) {
     if (!value->IsInteger() || value->GetDoubleValue() == 0)
       return Invalid();
-    if (!css_property_parser_helpers::ConsumeSlashIncludingWhitespace(range))
+    if (!css_parsing_utils::ConsumeSlashIncludingWhitespace(range))
       return Invalid();
     CSSPrimitiveValue* denominator =
-        css_property_parser_helpers::ConsumePositiveInteger(range, context);
+        css_parsing_utils::ConsumePositiveInteger(range, context);
     if (!denominator)
       return Invalid();
 
diff --git a/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc b/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc
index 05ff290..acba8a7 100644
--- a/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc
+++ b/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc
@@ -31,13 +31,13 @@
       // 'all' is only allowed in @font-face and with no other values.
       if (values->length())
         return nullptr;
-      return css_property_parser_helpers::ConsumeIdent(range);
+      return css_parsing_utils::ConsumeIdent(range);
     }
     CSSIdentifierValue* font_variant =
         css_parsing_utils::ConsumeFontVariantCSS21(range);
     if (font_variant)
       values->Append(*font_variant);
-  } while (css_property_parser_helpers::ConsumeCommaIncludingWhitespace(range));
+  } while (css_parsing_utils::ConsumeCommaIncludingWhitespace(range));
 
   if (values->length())
     return values;
@@ -46,7 +46,7 @@
 }
 
 CSSIdentifierValue* ConsumeFontDisplay(CSSParserTokenRange& range) {
-  return css_property_parser_helpers::ConsumeIdent<
+  return css_parsing_utils::ConsumeIdent<
       CSSValueID::kAuto, CSSValueID::kBlock, CSSValueID::kSwap,
       CSSValueID::kFallback, CSSValueID::kOptional>(range);
 }
@@ -65,7 +65,7 @@
       return nullptr;
     values->Append(
         *MakeGarbageCollected<cssvalue::CSSUnicodeRangeValue>(start, end));
-  } while (css_property_parser_helpers::ConsumeCommaIncludingWhitespace(range));
+  } while (css_parsing_utils::ConsumeCommaIncludingWhitespace(range));
 
   return values;
 }
@@ -73,8 +73,7 @@
 CSSValue* ConsumeFontFaceSrcURI(CSSParserTokenRange& range,
                                 const CSSParserContext& context) {
   String url =
-      css_property_parser_helpers::ConsumeUrlAsStringView(range, context)
-          .ToString();
+      css_parsing_utils::ConsumeUrlAsStringView(range, context).ToString();
   if (url.IsNull())
     return nullptr;
   CSSFontFaceSrcValue* uri_value(CSSFontFaceSrcValue::Create(
@@ -89,8 +88,7 @@
   // FIXME: https://drafts.csswg.org/css-fonts says that format() contains a
   // comma-separated list of strings, but CSSFontFaceSrcValue stores only one
   // format. Allowing one format for now.
-  CSSParserTokenRange args =
-      css_property_parser_helpers::ConsumeFunction(range);
+  CSSParserTokenRange args = css_parsing_utils::ConsumeFunction(range);
   const CSSParserToken& arg = args.ConsumeIncludingWhitespace();
   if ((arg.GetType() != kStringToken) || !args.AtEnd())
     return nullptr;
@@ -100,8 +98,7 @@
 
 CSSValue* ConsumeFontFaceSrcLocal(CSSParserTokenRange& range,
                                   const CSSParserContext& context) {
-  CSSParserTokenRange args =
-      css_property_parser_helpers::ConsumeFunction(range);
+  CSSParserTokenRange args = css_parsing_utils::ConsumeFunction(range);
   network::mojom::CSPDisposition should_check_content_security_policy =
       context.ShouldCheckContentSecurityPolicy();
   if (args.Peek().GetType() == kStringToken) {
@@ -140,7 +137,7 @@
     if (!parsed_value)
       return nullptr;
     values->Append(*parsed_value);
-  } while (css_property_parser_helpers::ConsumeCommaIncludingWhitespace(range));
+  } while (css_parsing_utils::ConsumeCommaIncludingWhitespace(range));
   return values;
 }
 
@@ -234,7 +231,7 @@
   switch (id) {
     case AtRuleDescriptorID::Syntax:
       range.ConsumeWhitespace();
-      parsed_value = css_property_parser_helpers::ConsumeString(range);
+      parsed_value = css_parsing_utils::ConsumeString(range);
       break;
     case AtRuleDescriptorID::InitialValue: {
       // Note that we must retain leading whitespace here.
@@ -243,9 +240,8 @@
     }
     case AtRuleDescriptorID::Inherits:
       range.ConsumeWhitespace();
-      parsed_value =
-          css_property_parser_helpers::ConsumeIdent<CSSValueID::kTrue,
-                                                    CSSValueID::kFalse>(range);
+      parsed_value = css_parsing_utils::ConsumeIdent<CSSValueID::kTrue,
+                                                     CSSValueID::kFalse>(range);
       break;
     default:
       break;
diff --git a/third_party/blink/renderer/core/css/parser/css_parser.cc b/third_party/blink/renderer/core/css/parser/css_parser.cc
index 37d310b..8a09099 100644
--- a/third_party/blink/renderer/core/css/parser/css_parser.cc
+++ b/third_party/blink/renderer/core/css/parser/css_parser.cc
@@ -11,11 +11,11 @@
 #include "third_party/blink/renderer/core/css/parser/css_parser_fast_paths.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_impl.h"
 #include "third_party/blink/renderer/core/css/parser/css_property_parser.h"
-#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
 #include "third_party/blink/renderer/core/css/parser/css_selector_parser.h"
 #include "third_party/blink/renderer/core/css/parser/css_supports_parser.h"
 #include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
 #include "third_party/blink/renderer/core/css/parser/css_variable_parser.h"
+#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
 #include "third_party/blink/renderer/core/css/style_color.h"
 #include "third_party/blink/renderer/core/css/style_rule.h"
 #include "third_party/blink/renderer/core/css/style_sheet_contents.h"
@@ -284,8 +284,8 @@
   CSSTokenizer tokenizer(string);
   const auto tokens = tokenizer.TokenizeToEOF();
   CSSParserTokenRange range(tokens);
-  return css_property_parser_helpers::ConsumeLengthOrPercent(range, *context,
-                                                             kValueRangeAll);
+  return css_parsing_utils::ConsumeLengthOrPercent(range, *context,
+                                                   kValueRangeAll);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser.cc b/third_party/blink/renderer/core/css/parser/css_property_parser.cc
index 8fcf3c5..b379cd4 100644
--- a/third_party/blink/renderer/core/css/parser/css_property_parser.cc
+++ b/third_party/blink/renderer/core/css/parser/css_property_parser.cc
@@ -14,7 +14,6 @@
 #include "third_party/blink/renderer/core/css/hash_tools.h"
 #include "third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_local_context.h"
-#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
 #include "third_party/blink/renderer/core/css/parser/css_variable_parser.h"
 #include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
 #include "third_party/blink/renderer/core/css/properties/css_property.h"
@@ -24,9 +23,9 @@
 
 namespace blink {
 
-using css_property_parser_helpers::ConsumeIdent;
-using css_property_parser_helpers::IsImplicitProperty;
-using css_property_parser_helpers::ParseLonghand;
+using css_parsing_utils::ConsumeIdent;
+using css_parsing_utils::IsImplicitProperty;
+using css_parsing_utils::ParseLonghand;
 
 class CSSIdentifierValue;
 
@@ -161,7 +160,7 @@
       const cssvalue::CSSPendingSubstitutionValue& pending_value =
           *MakeGarbageCollected<cssvalue::CSSPendingSubstitutionValue>(
               property_id, variable);
-      css_property_parser_helpers::AddExpandedPropertyForValue(
+      css_parsing_utils::AddExpandedPropertyForValue(
           property_id, pending_value, important, *parsed_properties_);
     } else {
       AddProperty(property_id, CSSPropertyID::kInvalid, *variable, important,
@@ -281,8 +280,8 @@
     AddProperty(property, CSSPropertyID::kInvalid, *value, important,
                 IsImplicitProperty::kNotImplicit, *parsed_properties_);
   } else {
-    css_property_parser_helpers::AddExpandedPropertyForValue(
-        property, *value, important, *parsed_properties_);
+    css_parsing_utils::AddExpandedPropertyForValue(property, *value, important,
+                                                   *parsed_properties_);
   }
   range_ = range_copy;
   return true;
@@ -300,19 +299,19 @@
     case CSSPropertyID::kMaxHeight:
       if (id == CSSValueID::kAuto || id == CSSValueID::kInternalExtendToZoom)
         return ConsumeIdent(range);
-      return css_property_parser_helpers::ConsumeLengthOrPercent(
-          range, context, kValueRangeNonNegative);
+      return css_parsing_utils::ConsumeLengthOrPercent(range, context,
+                                                       kValueRangeNonNegative);
     case CSSPropertyID::kMinZoom:
     case CSSPropertyID::kMaxZoom:
     case CSSPropertyID::kZoom: {
       if (id == CSSValueID::kAuto)
         return ConsumeIdent(range);
-      CSSValue* parsed_value = css_property_parser_helpers::ConsumeNumber(
+      CSSValue* parsed_value = css_parsing_utils::ConsumeNumber(
           range, context, kValueRangeNonNegative);
       if (parsed_value)
         return parsed_value;
-      return css_property_parser_helpers::ConsumePercent(
-          range, context, kValueRangeNonNegative);
+      return css_parsing_utils::ConsumePercent(range, context,
+                                               kValueRangeNonNegative);
     }
     case CSSPropertyID::kUserZoom:
       return ConsumeIdent<CSSValueID::kZoom, CSSValueID::kFixed>(range);
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
deleted file mode 100644
index 4cff58b..0000000
--- a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
+++ /dev/null
@@ -1,2215 +0,0 @@
-// Copyright 2016 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/css/parser/css_property_parser_helpers.h"
-
-#include "third_party/blink/renderer/core/css/css_axis_value.h"
-#include "third_party/blink/renderer/core/css/css_color_value.h"
-#include "third_party/blink/renderer/core/css/css_crossfade_value.h"
-#include "third_party/blink/renderer/core/css/css_gradient_value.h"
-#include "third_party/blink/renderer/core/css/css_image_set_value.h"
-#include "third_party/blink/renderer/core/css/css_image_value.h"
-#include "third_party/blink/renderer/core/css/css_initial_value.h"
-#include "third_party/blink/renderer/core/css/css_light_dark_value_pair.h"
-#include "third_party/blink/renderer/core/css/css_math_expression_node.h"
-#include "third_party/blink/renderer/core/css/css_math_function_value.h"
-#include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
-#include "third_party/blink/renderer/core/css/css_paint_value.h"
-#include "third_party/blink/renderer/core/css/css_property_value.h"
-#include "third_party/blink/renderer/core/css/css_shadow_value.h"
-#include "third_party/blink/renderer/core/css/css_string_value.h"
-#include "third_party/blink/renderer/core/css/css_uri_value.h"
-#include "third_party/blink/renderer/core/css/css_value_pair.h"
-#include "third_party/blink/renderer/core/css/css_variable_data.h"
-#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
-#include "third_party/blink/renderer/core/css/parser/css_parser_fast_paths.h"
-#include "third_party/blink/renderer/core/css/parser/css_parser_local_context.h"
-#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
-#include "third_party/blink/renderer/core/css/properties/css_property.h"
-#include "third_party/blink/renderer/core/css/properties/longhand.h"
-#include "third_party/blink/renderer/core/css/style_color.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/web_feature.h"
-#include "third_party/blink/renderer/core/inspector/console_message.h"
-#include "third_party/blink/renderer/core/style_property_shorthand.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-
-namespace blink {
-
-namespace css_property_parser_helpers {
-
-namespace {
-
-// Add CSSVariableData to variableData vector.
-bool AddCSSPaintArgument(
-    const Vector<CSSParserToken>& tokens,
-    Vector<scoped_refptr<CSSVariableData>>* const variable_data,
-    const CSSParserContext& context) {
-  CSSParserTokenRange token_range(tokens);
-  if (!token_range.AtEnd()) {
-    scoped_refptr<CSSVariableData> unparsed_css_variable_data =
-        CSSVariableData::Create(token_range, false, false, context.BaseURL(),
-                                context.Charset());
-    if (unparsed_css_variable_data.get()) {
-      variable_data->push_back(std::move(unparsed_css_variable_data));
-      return true;
-    }
-  }
-  return false;
-}
-
-// Consume input arguments, if encounter function, will return the function
-// block as a Vector of CSSParserToken, otherwise, will just return a Vector of
-// a single CSSParserToken.
-Vector<CSSParserToken> ConsumeFunctionArgsOrNot(CSSParserTokenRange& args) {
-  Vector<CSSParserToken> argument_tokens;
-  if (args.Peek().GetBlockType() == CSSParserToken::kBlockStart) {
-    // Function block.
-    // Push the function name and initial right parenthesis.
-    // Since we don't have any upfront knowledge about the input argument types
-    // here, we should just leave the token as it is and resolve it later in
-    // the variable parsing phase.
-    argument_tokens.push_back(args.Peek());
-    CSSParserTokenRange contents = args.ConsumeBlock();
-    while (!contents.AtEnd()) {
-      argument_tokens.push_back(contents.Consume());
-    }
-    argument_tokens.push_back(
-        CSSParserToken(kRightParenthesisToken, CSSParserToken::kBlockEnd));
-
-  } else {
-    argument_tokens.push_back(args.ConsumeIncludingWhitespace());
-  }
-  return argument_tokens;
-}
-
-CSSFunctionValue* ConsumeFilterFunction(CSSParserTokenRange& range,
-                                        const CSSParserContext& context) {
-  CSSValueID filter_type = range.Peek().FunctionId();
-  if (filter_type < CSSValueID::kInvert ||
-      filter_type > CSSValueID::kDropShadow)
-    return nullptr;
-  CSSParserTokenRange args =
-      css_property_parser_helpers::ConsumeFunction(range);
-  CSSFunctionValue* filter_value =
-      MakeGarbageCollected<CSSFunctionValue>(filter_type);
-  CSSValue* parsed_value = nullptr;
-
-  if (filter_type == CSSValueID::kDropShadow) {
-    parsed_value = css_parsing_utils::ParseSingleShadow(
-        args, context, css_parsing_utils::AllowInsetAndSpread::kForbid);
-  } else {
-    if (args.AtEnd()) {
-      context.Count(WebFeature::kCSSFilterFunctionNoArguments);
-      return filter_value;
-    }
-    if (filter_type == CSSValueID::kBrightness) {
-      // FIXME (crbug.com/397061): Support calc expressions like calc(10% + 0.5)
-      parsed_value = css_property_parser_helpers::ConsumePercent(
-          args, context, kValueRangeAll);
-      if (!parsed_value) {
-        parsed_value = css_property_parser_helpers::ConsumeNumber(
-            args, context, kValueRangeNonNegative);
-      }
-    } else if (filter_type == CSSValueID::kHueRotate) {
-      parsed_value = css_property_parser_helpers::ConsumeAngle(
-          args, context, WebFeature::kUnitlessZeroAngleFilter);
-    } else if (filter_type == CSSValueID::kBlur) {
-      CSSParserContext::ParserModeOverridingScope scope(context,
-                                                        kHTMLStandardMode);
-      parsed_value = css_property_parser_helpers::ConsumeLength(
-          args, context, kValueRangeNonNegative);
-    } else {
-      // FIXME (crbug.com/397061): Support calc expressions like calc(10% + 0.5)
-      parsed_value = css_property_parser_helpers::ConsumePercent(
-          args, context, kValueRangeNonNegative);
-      if (!parsed_value) {
-        parsed_value = css_property_parser_helpers::ConsumeNumber(
-            args, context, kValueRangeNonNegative);
-      }
-      if (parsed_value && filter_type != CSSValueID::kSaturate &&
-          filter_type != CSSValueID::kContrast) {
-        bool is_percentage =
-            To<CSSPrimitiveValue>(parsed_value)->IsPercentage();
-        double max_allowed = is_percentage ? 100.0 : 1.0;
-        if (To<CSSPrimitiveValue>(parsed_value)->GetDoubleValue() >
-            max_allowed) {
-          parsed_value = CSSNumericLiteralValue::Create(
-              max_allowed, is_percentage
-                               ? CSSPrimitiveValue::UnitType::kPercentage
-                               : CSSPrimitiveValue::UnitType::kNumber);
-        }
-      }
-    }
-  }
-  if (!parsed_value || !args.AtEnd())
-    return nullptr;
-  filter_value->Append(*parsed_value);
-  return filter_value;
-}
-
-template <typename Func, typename... Args>
-CSSLightDarkValuePair* ConsumeInternalLightDark(Func consume_value,
-                                                CSSParserTokenRange& range,
-                                                const CSSParserContext& context,
-                                                Args&&... args) {
-  if (range.Peek().FunctionId() != CSSValueID::kInternalLightDark)
-    return nullptr;
-  if (!isValueAllowedInMode(CSSValueID::kInternalLightDark, context.Mode()))
-    return nullptr;
-  CSSParserTokenRange range_copy = range;
-  CSSParserTokenRange arg_range = ConsumeFunction(range_copy);
-  CSSValue* light_value =
-      consume_value(arg_range, context, std::forward<Args>(args)...);
-  if (!light_value || !ConsumeCommaIncludingWhitespace(arg_range))
-    return nullptr;
-  CSSValue* dark_value =
-      consume_value(arg_range, context, std::forward<Args>(args)...);
-  if (!dark_value || !arg_range.AtEnd())
-    return nullptr;
-  range = range_copy;
-  return MakeGarbageCollected<CSSLightDarkValuePair>(light_value, dark_value);
-}
-
-}  // namespace
-
-void Complete4Sides(CSSValue* side[4]) {
-  if (side[3])
-    return;
-  if (!side[2]) {
-    if (!side[1])
-      side[1] = side[0];
-    side[2] = side[0];
-  }
-  side[3] = side[1];
-}
-
-bool ConsumeCommaIncludingWhitespace(CSSParserTokenRange& range) {
-  CSSParserToken value = range.Peek();
-  if (value.GetType() != kCommaToken)
-    return false;
-  range.ConsumeIncludingWhitespace();
-  return true;
-}
-
-bool ConsumeSlashIncludingWhitespace(CSSParserTokenRange& range) {
-  CSSParserToken value = range.Peek();
-  if (value.GetType() != kDelimiterToken || value.Delimiter() != '/')
-    return false;
-  range.ConsumeIncludingWhitespace();
-  return true;
-}
-
-CSSParserTokenRange ConsumeFunction(CSSParserTokenRange& range) {
-  DCHECK_EQ(range.Peek().GetType(), kFunctionToken);
-  CSSParserTokenRange contents = range.ConsumeBlock();
-  range.ConsumeWhitespace();
-  contents.ConsumeWhitespace();
-  return contents;
-}
-
-// TODO(rwlbuis): consider pulling in the parsing logic from
-// css_math_expression_node.cc.
-class MathFunctionParser {
-  STACK_ALLOCATED();
-
- public:
-  MathFunctionParser(CSSParserTokenRange& range,
-                     const CSSParserContext& context,
-                     ValueRange value_range)
-      : source_range_(range), range_(range) {
-    const CSSParserToken& token = range.Peek();
-    switch (token.FunctionId()) {
-      case CSSValueID::kCalc:
-      case CSSValueID::kWebkitCalc:
-        calc_value_ = CSSMathFunctionValue::Create(
-            CSSMathExpressionNode::ParseCalc(ConsumeFunction(range_)),
-            value_range);
-        break;
-      case CSSValueID::kMin:
-        calc_value_ = CSSMathFunctionValue::Create(
-            CSSMathExpressionNode::ParseMin(ConsumeFunction(range_)),
-            value_range);
-        break;
-      case CSSValueID::kMax:
-        calc_value_ = CSSMathFunctionValue::Create(
-            CSSMathExpressionNode::ParseMax(ConsumeFunction(range_)),
-            value_range);
-        break;
-      case CSSValueID::kClamp:
-        calc_value_ = CSSMathFunctionValue::Create(
-            CSSMathExpressionNode::ParseClamp(ConsumeFunction(range_)),
-            value_range);
-        break;
-      default:
-        break;
-    }
-    if (calc_value_ && calc_value_->HasComparisons())
-      context.Count(WebFeature::kCSSComparisonFunctions);
-  }
-
-  explicit MathFunctionParser(CSSParserTokenRange& range,
-                              const CSSParserContext& context)
-      : MathFunctionParser(range, context, kValueRangeAll) {}
-
-  const CSSMathFunctionValue* Value() const { return calc_value_; }
-  CSSMathFunctionValue* ConsumeValue() {
-    if (!calc_value_)
-      return nullptr;
-    source_range_ = range_;
-    CSSMathFunctionValue* result = calc_value_;
-    calc_value_ = nullptr;
-    return result;
-  }
-
-  CSSPrimitiveValue* ConsumeRoundedInt() {
-    if (!calc_value_)
-      return nullptr;
-    source_range_ = range_;
-    CSSPrimitiveValue::UnitType unit_type =
-        CSSPrimitiveValue::UnitType::kInteger;
-    double rounded_value = floor(calc_value_->GetDoubleValue() + 0.5);
-    return CSSNumericLiteralValue::Create(rounded_value, unit_type);
-  }
-
-  CSSPrimitiveValue* ConsumeNumber() {
-    if (!calc_value_)
-      return nullptr;
-    source_range_ = range_;
-    CSSPrimitiveValue::UnitType unit_type =
-        calc_value_->IsInt() ? CSSPrimitiveValue::UnitType::kInteger
-                             : CSSPrimitiveValue::UnitType::kNumber;
-    return CSSNumericLiteralValue::Create(calc_value_->GetDoubleValue(),
-                                          unit_type);
-  }
-
-  bool ConsumeNumberRaw(double& result) {
-    if (!calc_value_ || calc_value_->Category() != kCalcNumber)
-      return false;
-    source_range_ = range_;
-    result = calc_value_->GetDoubleValue();
-    return true;
-  }
-
- private:
-  CSSParserTokenRange& source_range_;
-  CSSParserTokenRange range_;
-  CSSMathFunctionValue* calc_value_ = nullptr;
-};
-
-CSSPrimitiveValue* ConsumeInteger(CSSParserTokenRange& range,
-                                  const CSSParserContext& context,
-                                  double minimum_value) {
-  const CSSParserToken& token = range.Peek();
-  if (token.GetType() == kNumberToken) {
-    if (token.GetNumericValueType() == kNumberValueType ||
-        token.NumericValue() < minimum_value)
-      return nullptr;
-    return CSSNumericLiteralValue::Create(
-        range.ConsumeIncludingWhitespace().NumericValue(),
-        CSSPrimitiveValue::UnitType::kInteger);
-  }
-  MathFunctionParser math_parser(range, context);
-  if (const CSSMathFunctionValue* math_value = math_parser.Value()) {
-    if (!RuntimeEnabledFeatures::CSSCalcAsIntEnabled() && !math_value->IsInt())
-      return nullptr;
-    if (math_value->Category() != kCalcNumber)
-      return nullptr;
-    double double_value = math_value->GetDoubleValue();
-    if (double_value < minimum_value)
-      return nullptr;
-    if (!RuntimeEnabledFeatures::CSSCalcAsIntEnabled())
-      return math_parser.ConsumeNumber();
-    if (math_value->IsInt())
-      return math_parser.ConsumeNumber();
-    return math_parser.ConsumeRoundedInt();
-  }
-  return nullptr;
-}
-
-// This implements the behavior defined in [1], where calc() expressions
-// are valid when <integer> is expected, even if the calc()-expression does
-// not result in an integral value.
-//
-// TODO(andruud): Eventually this behavior should just be part of
-// ConsumeInteger, and this function can be removed. For now, having a separate
-// function with this behavior allows us to implement [1] gradually.
-//
-// [1] https://drafts.csswg.org/css-values-4/#calc-type-checking
-CSSPrimitiveValue* ConsumeIntegerOrNumberCalc(CSSParserTokenRange& range,
-                                              const CSSParserContext& context) {
-  CSSParserTokenRange int_range(range);
-  if (CSSPrimitiveValue* value = ConsumeInteger(int_range, context)) {
-    range = int_range;
-    return value;
-  }
-  MathFunctionParser math_parser(range, context);
-  if (const CSSMathFunctionValue* calculation = math_parser.Value()) {
-    if (calculation->Category() != kCalcNumber)
-      return nullptr;
-    return math_parser.ConsumeValue();
-  }
-  return nullptr;
-}
-
-CSSPrimitiveValue* ConsumePositiveInteger(CSSParserTokenRange& range,
-                                          const CSSParserContext& context) {
-  return ConsumeInteger(range, context, 1);
-}
-
-bool ConsumeNumberRaw(CSSParserTokenRange& range,
-                      const CSSParserContext& context,
-                      double& result) {
-  if (range.Peek().GetType() == kNumberToken) {
-    result = range.ConsumeIncludingWhitespace().NumericValue();
-    return true;
-  }
-  MathFunctionParser math_parser(range, context, kValueRangeAll);
-  return math_parser.ConsumeNumberRaw(result);
-}
-
-// TODO(timloh): Work out if this can just call consumeNumberRaw
-CSSPrimitiveValue* ConsumeNumber(CSSParserTokenRange& range,
-                                 const CSSParserContext& context,
-                                 ValueRange value_range) {
-  const CSSParserToken& token = range.Peek();
-  if (token.GetType() == kNumberToken) {
-    if (value_range == kValueRangeNonNegative && token.NumericValue() < 0)
-      return nullptr;
-    return CSSNumericLiteralValue::Create(
-        range.ConsumeIncludingWhitespace().NumericValue(), token.GetUnitType());
-  }
-  MathFunctionParser math_parser(range, context, kValueRangeAll);
-  if (const CSSMathFunctionValue* calculation = math_parser.Value()) {
-    // TODO(rwlbuis) Calcs should not be subject to parse time range checks.
-    // spec: https://drafts.csswg.org/css-values-3/#calc-range
-    if (calculation->Category() != kCalcNumber ||
-        (value_range == kValueRangeNonNegative && calculation->IsNegative()))
-      return nullptr;
-    return math_parser.ConsumeNumber();
-  }
-  return nullptr;
-}
-
-inline bool ShouldAcceptUnitlessLength(double value,
-                                       CSSParserMode css_parser_mode,
-                                       UnitlessQuirk unitless) {
-  return value == 0 || css_parser_mode == kSVGAttributeMode ||
-         (css_parser_mode == kHTMLQuirksMode &&
-          unitless == UnitlessQuirk::kAllow);
-}
-
-CSSPrimitiveValue* ConsumeLength(CSSParserTokenRange& range,
-                                 const CSSParserContext& context,
-                                 ValueRange value_range,
-                                 UnitlessQuirk unitless) {
-  const CSSParserToken& token = range.Peek();
-  if (token.GetType() == kDimensionToken) {
-    switch (token.GetUnitType()) {
-      case CSSPrimitiveValue::UnitType::kQuirkyEms:
-        if (context.Mode() != kUASheetMode)
-          return nullptr;
-        FALLTHROUGH;
-      case CSSPrimitiveValue::UnitType::kEms:
-      case CSSPrimitiveValue::UnitType::kRems:
-      case CSSPrimitiveValue::UnitType::kChs:
-      case CSSPrimitiveValue::UnitType::kExs:
-      case CSSPrimitiveValue::UnitType::kPixels:
-      case CSSPrimitiveValue::UnitType::kCentimeters:
-      case CSSPrimitiveValue::UnitType::kMillimeters:
-      case CSSPrimitiveValue::UnitType::kQuarterMillimeters:
-      case CSSPrimitiveValue::UnitType::kInches:
-      case CSSPrimitiveValue::UnitType::kPoints:
-      case CSSPrimitiveValue::UnitType::kPicas:
-      case CSSPrimitiveValue::UnitType::kUserUnits:
-      case CSSPrimitiveValue::UnitType::kViewportWidth:
-      case CSSPrimitiveValue::UnitType::kViewportHeight:
-      case CSSPrimitiveValue::UnitType::kViewportMin:
-      case CSSPrimitiveValue::UnitType::kViewportMax:
-        break;
-      default:
-        return nullptr;
-    }
-    if (value_range == kValueRangeNonNegative && token.NumericValue() < 0)
-      return nullptr;
-    return CSSNumericLiteralValue::Create(
-        range.ConsumeIncludingWhitespace().NumericValue(), token.GetUnitType());
-  }
-  if (token.GetType() == kNumberToken) {
-    if (!ShouldAcceptUnitlessLength(token.NumericValue(), context.Mode(),
-                                    unitless) ||
-        (value_range == kValueRangeNonNegative && token.NumericValue() < 0))
-      return nullptr;
-    CSSPrimitiveValue::UnitType unit_type =
-        CSSPrimitiveValue::UnitType::kPixels;
-    if (context.Mode() == kSVGAttributeMode)
-      unit_type = CSSPrimitiveValue::UnitType::kUserUnits;
-    return CSSNumericLiteralValue::Create(
-        range.ConsumeIncludingWhitespace().NumericValue(), unit_type);
-  }
-  if (context.Mode() == kSVGAttributeMode)
-    return nullptr;
-  MathFunctionParser math_parser(range, context, value_range);
-  if (math_parser.Value() && math_parser.Value()->Category() == kCalcLength)
-    return math_parser.ConsumeValue();
-  return nullptr;
-}
-
-CSSPrimitiveValue* ConsumePercent(CSSParserTokenRange& range,
-                                  const CSSParserContext& context,
-                                  ValueRange value_range) {
-  const CSSParserToken& token = range.Peek();
-  if (token.GetType() == kPercentageToken) {
-    if (value_range == kValueRangeNonNegative && token.NumericValue() < 0)
-      return nullptr;
-    return CSSNumericLiteralValue::Create(
-        range.ConsumeIncludingWhitespace().NumericValue(),
-        CSSPrimitiveValue::UnitType::kPercentage);
-  }
-  MathFunctionParser math_parser(range, context, value_range);
-  if (const CSSMathFunctionValue* calculation = math_parser.Value()) {
-    if (calculation->Category() == kCalcPercent)
-      return math_parser.ConsumeValue();
-  }
-  return nullptr;
-}
-
-CSSPrimitiveValue* ConsumeAlphaValue(CSSParserTokenRange& range,
-                                     const CSSParserContext& context) {
-  if (CSSPrimitiveValue* value =
-          ConsumeNumber(range, context, kValueRangeAll)) {
-    return value;
-  }
-  if (CSSPrimitiveValue* value =
-          ConsumePercent(range, context, kValueRangeAll)) {
-    return CSSNumericLiteralValue::Create(value->GetDoubleValue() / 100.0,
-                                          CSSPrimitiveValue::UnitType::kNumber);
-  }
-  return nullptr;
-}
-
-bool CanConsumeCalcValue(CalculationCategory category,
-                         CSSParserMode css_parser_mode) {
-  return category == kCalcLength || category == kCalcPercent ||
-         category == kCalcPercentLength ||
-         (css_parser_mode == kSVGAttributeMode && category == kCalcNumber);
-}
-
-CSSPrimitiveValue* ConsumeLengthOrPercent(CSSParserTokenRange& range,
-                                          const CSSParserContext& context,
-                                          ValueRange value_range,
-                                          UnitlessQuirk unitless) {
-  const CSSParserToken& token = range.Peek();
-  if (token.GetType() == kDimensionToken || token.GetType() == kNumberToken)
-    return ConsumeLength(range, context, value_range, unitless);
-  if (token.GetType() == kPercentageToken)
-    return ConsumePercent(range, context, value_range);
-  MathFunctionParser math_parser(range, context, value_range);
-  if (const CSSMathFunctionValue* calculation = math_parser.Value()) {
-    if (CanConsumeCalcValue(calculation->Category(), context.Mode()))
-      return math_parser.ConsumeValue();
-  }
-  return nullptr;
-}
-
-namespace {
-
-bool IsNonZeroUserUnitsValue(const CSSPrimitiveValue* value) {
-  if (!value)
-    return false;
-  if (const auto* numeric_literal = DynamicTo<CSSNumericLiteralValue>(value)) {
-    return numeric_literal->GetType() ==
-               CSSPrimitiveValue::UnitType::kUserUnits &&
-           value->GetDoubleValue() != 0;
-  }
-  const auto& math_value = To<CSSMathFunctionValue>(*value);
-  return math_value.Category() == kCalcNumber && math_value.DoubleValue() != 0;
-}
-
-}  // namespace
-
-CSSPrimitiveValue* ConsumeSVGGeometryPropertyLength(
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    ValueRange value_range) {
-  CSSParserContext::ParserModeOverridingScope scope(context, kSVGAttributeMode);
-  CSSPrimitiveValue* value = ConsumeLengthOrPercent(range, context, value_range,
-                                                    UnitlessQuirk::kForbid);
-  if (IsNonZeroUserUnitsValue(value))
-    context.Count(WebFeature::kSVGGeometryPropertyHasNonZeroUnitlessValue);
-  return value;
-}
-
-CSSPrimitiveValue* ConsumeGradientLengthOrPercent(
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    ValueRange value_range,
-    UnitlessQuirk unitless) {
-  return ConsumeLengthOrPercent(range, context, value_range, unitless);
-}
-
-CSSPrimitiveValue* ConsumeAngle(
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    base::Optional<WebFeature> unitless_zero_feature,
-    double minimum_value,
-    double maximum_value) {
-  const CSSParserToken& token = range.Peek();
-  if (token.GetType() == kDimensionToken) {
-    switch (token.GetUnitType()) {
-      case CSSPrimitiveValue::UnitType::kDegrees:
-      case CSSPrimitiveValue::UnitType::kRadians:
-      case CSSPrimitiveValue::UnitType::kGradians:
-      case CSSPrimitiveValue::UnitType::kTurns:
-        return CSSNumericLiteralValue::Create(
-            range.ConsumeIncludingWhitespace().NumericValue(),
-            token.GetUnitType());
-      default:
-        return nullptr;
-    }
-  }
-  if (token.GetType() == kNumberToken && token.NumericValue() == 0 &&
-      unitless_zero_feature) {
-    range.ConsumeIncludingWhitespace();
-    context.Count(*unitless_zero_feature);
-    return CSSNumericLiteralValue::Create(
-        0, CSSPrimitiveValue::UnitType::kDegrees);
-  }
-  MathFunctionParser math_parser(range, context, kValueRangeAll);
-  if (const CSSMathFunctionValue* calculation = math_parser.Value()) {
-    if (calculation->Category() != kCalcAngle)
-      return nullptr;
-    if (CSSMathFunctionValue* result = math_parser.ConsumeValue()) {
-      if (result->ComputeDegrees() < minimum_value) {
-        return CSSNumericLiteralValue::Create(
-            minimum_value, CSSPrimitiveValue::UnitType::kDegrees);
-      }
-      if (result->ComputeDegrees() > maximum_value) {
-        return CSSNumericLiteralValue::Create(
-            maximum_value, CSSPrimitiveValue::UnitType::kDegrees);
-      }
-      return result;
-    }
-  }
-  return nullptr;
-}
-
-CSSPrimitiveValue* ConsumeAngle(
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    base::Optional<WebFeature> unitless_zero_feature) {
-  return ConsumeAngle(range, context, std::move(unitless_zero_feature),
-                      std::numeric_limits<double>::lowest(),
-                      std::numeric_limits<double>::max());
-}
-
-CSSPrimitiveValue* ConsumeTime(CSSParserTokenRange& range,
-                               const CSSParserContext& context,
-                               ValueRange value_range) {
-  const CSSParserToken& token = range.Peek();
-  if (token.GetType() == kDimensionToken) {
-    if (value_range == kValueRangeNonNegative && token.NumericValue() < 0)
-      return nullptr;
-    CSSPrimitiveValue::UnitType unit = token.GetUnitType();
-    if (unit == CSSPrimitiveValue::UnitType::kMilliseconds ||
-        unit == CSSPrimitiveValue::UnitType::kSeconds)
-      return CSSNumericLiteralValue::Create(
-          range.ConsumeIncludingWhitespace().NumericValue(),
-          token.GetUnitType());
-    return nullptr;
-  }
-  MathFunctionParser math_parser(range, context, value_range);
-  if (const CSSMathFunctionValue* calculation = math_parser.Value()) {
-    if (calculation->Category() == kCalcTime)
-      return math_parser.ConsumeValue();
-  }
-  return nullptr;
-}
-
-CSSPrimitiveValue* ConsumeResolution(CSSParserTokenRange& range) {
-  const CSSParserToken& token = range.Peek();
-  // Unlike the other types, calc() does not work with <resolution>.
-  if (token.GetType() != kDimensionToken)
-    return nullptr;
-  CSSPrimitiveValue::UnitType unit = token.GetUnitType();
-  if (unit == CSSPrimitiveValue::UnitType::kDotsPerPixel ||
-      unit == CSSPrimitiveValue::UnitType::kDotsPerInch ||
-      unit == CSSPrimitiveValue::UnitType::kDotsPerCentimeter) {
-    return CSSNumericLiteralValue::Create(
-        range.ConsumeIncludingWhitespace().NumericValue(), unit);
-  }
-  return nullptr;
-}
-
-CSSIdentifierValue* ConsumeIdent(CSSParserTokenRange& range) {
-  if (range.Peek().GetType() != kIdentToken)
-    return nullptr;
-  return CSSIdentifierValue::Create(range.ConsumeIncludingWhitespace().Id());
-}
-
-CSSIdentifierValue* ConsumeIdentRange(CSSParserTokenRange& range,
-                                      CSSValueID lower,
-                                      CSSValueID upper) {
-  if (range.Peek().Id() < lower || range.Peek().Id() > upper)
-    return nullptr;
-  return ConsumeIdent(range);
-}
-
-CSSCustomIdentValue* ConsumeCustomIdentWithToken(
-    const CSSParserToken& token,
-    const CSSParserContext& context) {
-  if (token.GetType() != kIdentToken || IsCSSWideKeyword(token.Value()))
-    return nullptr;
-
-  if (EqualIgnoringASCIICase(token.Value(), "default"))
-    context.Count(WebFeature::kDefaultInCustomIdent);
-
-  return MakeGarbageCollected<CSSCustomIdentValue>(
-      token.Value().ToAtomicString());
-}
-
-CSSCustomIdentValue* ConsumeCustomIdent(CSSParserTokenRange& range,
-                                        const CSSParserContext& context) {
-  if (range.Peek().GetType() != kIdentToken ||
-      IsCSSWideKeyword(range.Peek().Value()))
-    return nullptr;
-
-  return ConsumeCustomIdentWithToken(range.ConsumeIncludingWhitespace(),
-                                     context);
-}
-
-CSSStringValue* ConsumeString(CSSParserTokenRange& range) {
-  if (range.Peek().GetType() != kStringToken)
-    return nullptr;
-  return MakeGarbageCollected<CSSStringValue>(
-      range.ConsumeIncludingWhitespace().Value().ToString());
-}
-
-StringView ConsumeUrlAsStringView(CSSParserTokenRange& range,
-                                  const CSSParserContext& context) {
-  StringView url;
-  const CSSParserToken& token = range.Peek();
-  if (token.GetType() == kUrlToken) {
-    range.ConsumeIncludingWhitespace();
-    url = token.Value();
-  } else if (token.FunctionId() == CSSValueID::kUrl) {
-    CSSParserTokenRange url_range = range;
-    CSSParserTokenRange url_args = url_range.ConsumeBlock();
-    const CSSParserToken& next = url_args.ConsumeIncludingWhitespace();
-    if (next.GetType() == kBadStringToken || !url_args.AtEnd())
-      return StringView();
-    DCHECK_EQ(next.GetType(), kStringToken);
-    range = url_range;
-    range.ConsumeWhitespace();
-    url = next.Value();
-  }
-
-  // Invalidate the URL if only data URLs are allowed and the protocol is not
-  // data.
-  if (!url.IsNull() &&
-      context.ResourceFetchRestriction() ==
-          ResourceFetchRestriction::kOnlyDataUrls &&
-      !ProtocolIs(url.ToString(), "data")) {
-    // The StringView must be instantiated with an empty string otherwise the
-    // URL will incorrectly be identified as null. The resource should behave as
-    // if it failed to load.
-    url = StringView("");
-  }
-
-  return url;
-}
-
-cssvalue::CSSURIValue* ConsumeUrl(CSSParserTokenRange& range,
-                                  const CSSParserContext& context) {
-  StringView url = ConsumeUrlAsStringView(range, context);
-  if (url.IsNull())
-    return nullptr;
-  AtomicString url_string(url.ToString());
-  return MakeGarbageCollected<cssvalue::CSSURIValue>(
-      url_string, context.CompleteURL(url_string));
-}
-
-static int ClampRGBComponent(const CSSPrimitiveValue& value) {
-  double result = value.GetDoubleValue();
-  if (value.IsPercentage()) {
-    // 2.55 cannot be precisely represented as a double
-    result = (result / 100.0) * 255.0;
-  }
-  return clampTo<int>(round(result), 0, 255);
-}
-
-static bool ParseRGBParameters(CSSParserTokenRange& range,
-                               const CSSParserContext& context,
-                               RGBA32& result) {
-  DCHECK(range.Peek().FunctionId() == CSSValueID::kRgb ||
-         range.Peek().FunctionId() == CSSValueID::kRgba);
-  CSSParserTokenRange args = ConsumeFunction(range);
-  CSSPrimitiveValue* color_parameter =
-      ConsumeNumber(args, context, kValueRangeAll);
-  if (!color_parameter)
-    color_parameter = ConsumePercent(args, context, kValueRangeAll);
-  if (!color_parameter)
-    return false;
-  const bool is_percent = color_parameter->IsPercentage();
-  int color_array[3];
-  color_array[0] = ClampRGBComponent(*color_parameter);
-  bool requires_commas = false;
-  for (int i = 1; i < 3; i++) {
-    if (ConsumeCommaIncludingWhitespace(args)) {
-      if (i != 1 && !requires_commas)
-        return false;
-      requires_commas = true;
-    } else if (requires_commas || args.AtEnd()) {
-      return false;
-    }
-    color_parameter = is_percent ? ConsumePercent(args, context, kValueRangeAll)
-                                 : ConsumeNumber(args, context, kValueRangeAll);
-    if (!color_parameter)
-      return false;
-    color_array[i] = ClampRGBComponent(*color_parameter);
-  }
-
-  bool comma_consumed = ConsumeCommaIncludingWhitespace(args);
-  bool slash_consumed = ConsumeSlashIncludingWhitespace(args);
-  if ((comma_consumed && !requires_commas) ||
-      (slash_consumed && requires_commas))
-    return false;
-  if (comma_consumed || slash_consumed) {
-    double alpha;
-    if (!ConsumeNumberRaw(args, context, alpha)) {
-      CSSPrimitiveValue* alpha_percent =
-          ConsumePercent(args, context, kValueRangeAll);
-      if (!alpha_percent)
-        return false;
-      else
-        alpha = alpha_percent->GetDoubleValue() / 100.0;
-    }
-    // W3 standard stipulates a 2.55 alpha value multiplication factor.
-    int alpha_component =
-        static_cast<int>(lround(clampTo<double>(alpha, 0.0, 1.0) * 255.0));
-    result = MakeRGBA(color_array[0], color_array[1], color_array[2],
-                      alpha_component);
-  } else {
-    result = MakeRGB(color_array[0], color_array[1], color_array[2]);
-  }
-  return args.AtEnd();
-}
-
-static bool ParseHSLParameters(CSSParserTokenRange& range,
-                               const CSSParserContext& context,
-                               RGBA32& result) {
-  DCHECK(range.Peek().FunctionId() == CSSValueID::kHsl ||
-         range.Peek().FunctionId() == CSSValueID::kHsla);
-  CSSParserTokenRange args = ConsumeFunction(range);
-  CSSPrimitiveValue* hsl_value = ConsumeAngle(args, context, base::nullopt);
-  double angle_value;
-  if (!hsl_value) {
-    hsl_value = ConsumeNumber(args, context, kValueRangeAll);
-    if (!hsl_value)
-      return false;
-    angle_value = hsl_value->GetDoubleValue();
-  } else {
-    angle_value = hsl_value->ComputeDegrees();
-  }
-  double color_array[3];
-  color_array[0] = fmod(fmod(angle_value, 360.0) + 360.0, 360.0) / 60.0;
-  bool requires_commas = false;
-  for (int i = 1; i < 3; i++) {
-    if (ConsumeCommaIncludingWhitespace(args)) {
-      if (i != 1 && !requires_commas)
-        return false;
-      requires_commas = true;
-    } else if (requires_commas || args.AtEnd()) {
-      return false;
-    }
-    hsl_value = ConsumePercent(args, context, kValueRangeAll);
-    if (!hsl_value)
-      return false;
-    double double_value = hsl_value->GetDoubleValue();
-    color_array[i] = clampTo<double>(double_value, 0.0, 100.0) /
-                     100.0;  // Needs to be value between 0 and 1.0.
-  }
-
-  double alpha = 1.0;
-  bool comma_consumed = ConsumeCommaIncludingWhitespace(args);
-  bool slash_consumed = ConsumeSlashIncludingWhitespace(args);
-  if ((comma_consumed && !requires_commas) ||
-      (slash_consumed && requires_commas))
-    return false;
-  if (comma_consumed || slash_consumed) {
-    if (!ConsumeNumberRaw(args, context, alpha)) {
-      CSSPrimitiveValue* alpha_percent =
-          ConsumePercent(args, context, kValueRangeAll);
-      if (!alpha_percent)
-        return false;
-      else
-        alpha = alpha_percent->GetDoubleValue() / 100.0;
-    }
-    alpha = clampTo<double>(alpha, 0.0, 1.0);
-  }
-  result =
-      MakeRGBAFromHSLA(color_array[0], color_array[1], color_array[2], alpha);
-  return args.AtEnd();
-}
-
-static bool ParseHexColor(CSSParserTokenRange& range,
-                          RGBA32& result,
-                          bool accept_quirky_colors) {
-  const CSSParserToken& token = range.Peek();
-  if (token.GetType() == kHashToken) {
-    if (!Color::ParseHexColor(token.Value(), result))
-      return false;
-  } else if (accept_quirky_colors) {
-    String color;
-    if (token.GetType() == kNumberToken || token.GetType() == kDimensionToken) {
-      if (token.GetNumericValueType() != kIntegerValueType ||
-          token.NumericValue() < 0. || token.NumericValue() >= 1000000.)
-        return false;
-      if (token.GetType() == kNumberToken)  // e.g. 112233
-        color = String::Format("%d", static_cast<int>(token.NumericValue()));
-      else  // e.g. 0001FF
-        color = String::Number(static_cast<int>(token.NumericValue())) +
-                token.Value().ToString();
-      while (color.length() < 6)
-        color = "0" + color;
-    } else if (token.GetType() == kIdentToken) {  // e.g. FF0000
-      color = token.Value().ToString();
-    }
-    unsigned length = color.length();
-    if (length != 3 && length != 6)
-      return false;
-    if (!Color::ParseHexColor(color, result))
-      return false;
-  } else {
-    return false;
-  }
-  range.ConsumeIncludingWhitespace();
-  return true;
-}
-
-static bool ParseColorFunction(CSSParserTokenRange& range,
-                               const CSSParserContext& context,
-                               RGBA32& result) {
-  CSSValueID function_id = range.Peek().FunctionId();
-  if (function_id < CSSValueID::kRgb || function_id > CSSValueID::kHsla)
-    return false;
-  CSSParserTokenRange color_range = range;
-  if ((function_id <= CSSValueID::kRgba &&
-       !ParseRGBParameters(color_range, context, result)) ||
-      (function_id >= CSSValueID::kHsl &&
-       !ParseHSLParameters(color_range, context, result)))
-    return false;
-  range = color_range;
-  return true;
-}
-
-CSSValue* ConsumeColor(CSSParserTokenRange& range,
-                       const CSSParserContext& context,
-                       bool accept_quirky_colors) {
-  CSSValueID id = range.Peek().Id();
-  if (StyleColor::IsColorKeyword(id)) {
-    if (!isValueAllowedInMode(id, context.Mode()))
-      return nullptr;
-    CSSIdentifierValue* color = ConsumeIdent(range);
-    return color;
-  }
-  RGBA32 color = Color::kTransparent;
-  if (!ParseHexColor(range, color, accept_quirky_colors) &&
-      !ParseColorFunction(range, context, color)) {
-    return ConsumeInternalLightDark(ConsumeColor, range, context,
-                                    accept_quirky_colors);
-  }
-  return cssvalue::CSSColorValue::Create(color);
-}
-
-CSSValue* ConsumeInternalForcedBackgroundColor(
-    CSSParserTokenRange& range,
-    const CSSParserContext& context) {
-  CSSValueID id = range.Peek().Id();
-  if (!StyleColor::IsColorKeyword(id))
-    return nullptr;
-  return ConsumeIdent(range);
-}
-
-CSSValue* ConsumeLineWidth(CSSParserTokenRange& range,
-                           const CSSParserContext& context,
-                           UnitlessQuirk unitless) {
-  CSSValueID id = range.Peek().Id();
-  if (id == CSSValueID::kThin || id == CSSValueID::kMedium ||
-      id == CSSValueID::kThick)
-    return ConsumeIdent(range);
-  return ConsumeLength(range, context, kValueRangeNonNegative, unitless);
-}
-
-static CSSValue* ConsumePositionComponent(CSSParserTokenRange& range,
-                                          const CSSParserContext& context,
-                                          UnitlessQuirk unitless,
-                                          bool& horizontal_edge,
-                                          bool& vertical_edge) {
-  if (range.Peek().GetType() != kIdentToken)
-    return ConsumeLengthOrPercent(range, context, kValueRangeAll, unitless);
-
-  CSSValueID id = range.Peek().Id();
-  if (id == CSSValueID::kLeft || id == CSSValueID::kRight) {
-    if (horizontal_edge)
-      return nullptr;
-    horizontal_edge = true;
-  } else if (id == CSSValueID::kTop || id == CSSValueID::kBottom) {
-    if (vertical_edge)
-      return nullptr;
-    vertical_edge = true;
-  } else if (id != CSSValueID::kCenter) {
-    return nullptr;
-  }
-  return ConsumeIdent(range);
-}
-
-static bool IsHorizontalPositionKeywordOnly(const CSSValue& value) {
-  auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
-  if (!identifier_value)
-    return false;
-  CSSValueID value_id = identifier_value->GetValueID();
-  return value_id == CSSValueID::kLeft || value_id == CSSValueID::kRight;
-}
-
-static bool IsVerticalPositionKeywordOnly(const CSSValue& value) {
-  auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
-  if (!identifier_value)
-    return false;
-  CSSValueID value_id = identifier_value->GetValueID();
-  return value_id == CSSValueID::kTop || value_id == CSSValueID::kBottom;
-}
-
-static void PositionFromOneValue(CSSValue* value,
-                                 CSSValue*& result_x,
-                                 CSSValue*& result_y) {
-  bool value_applies_to_y_axis_only = IsVerticalPositionKeywordOnly(*value);
-  result_x = value;
-  result_y = CSSIdentifierValue::Create(CSSValueID::kCenter);
-  if (value_applies_to_y_axis_only)
-    std::swap(result_x, result_y);
-}
-
-static void PositionFromTwoValues(CSSValue* value1,
-                                  CSSValue* value2,
-                                  CSSValue*& result_x,
-                                  CSSValue*& result_y) {
-  bool must_order_as_xy = IsHorizontalPositionKeywordOnly(*value1) ||
-                          IsVerticalPositionKeywordOnly(*value2) ||
-                          !value1->IsIdentifierValue() ||
-                          !value2->IsIdentifierValue();
-  bool must_order_as_yx = IsVerticalPositionKeywordOnly(*value1) ||
-                          IsHorizontalPositionKeywordOnly(*value2);
-  DCHECK(!must_order_as_xy || !must_order_as_yx);
-  result_x = value1;
-  result_y = value2;
-  if (must_order_as_yx)
-    std::swap(result_x, result_y);
-}
-
-static void PositionFromThreeOrFourValues(CSSValue** values,
-                                          CSSValue*& result_x,
-                                          CSSValue*& result_y) {
-  CSSIdentifierValue* center = nullptr;
-  for (int i = 0; values[i]; i++) {
-    auto* current_value = To<CSSIdentifierValue>(values[i]);
-    CSSValueID id = current_value->GetValueID();
-
-    if (id == CSSValueID::kCenter) {
-      DCHECK(!center);
-      center = current_value;
-      continue;
-    }
-
-    CSSValue* result = nullptr;
-    if (values[i + 1] && !values[i + 1]->IsIdentifierValue()) {
-      result = MakeGarbageCollected<CSSValuePair>(
-          current_value, values[++i], CSSValuePair::kKeepIdenticalValues);
-    } else {
-      result = current_value;
-    }
-
-    if (id == CSSValueID::kLeft || id == CSSValueID::kRight) {
-      DCHECK(!result_x);
-      result_x = result;
-    } else {
-      DCHECK(id == CSSValueID::kTop || id == CSSValueID::kBottom);
-      DCHECK(!result_y);
-      result_y = result;
-    }
-  }
-
-  if (center) {
-    DCHECK(!!result_x != !!result_y);
-    if (!result_x)
-      result_x = center;
-    else
-      result_y = center;
-  }
-
-  DCHECK(result_x && result_y);
-}
-
-bool ConsumePosition(CSSParserTokenRange& range,
-                     const CSSParserContext& context,
-                     UnitlessQuirk unitless,
-                     base::Optional<WebFeature> three_value_position,
-                     CSSValue*& result_x,
-                     CSSValue*& result_y) {
-  bool horizontal_edge = false;
-  bool vertical_edge = false;
-  CSSValue* value1 = ConsumePositionComponent(range, context, unitless,
-                                              horizontal_edge, vertical_edge);
-  if (!value1)
-    return false;
-  if (!value1->IsIdentifierValue())
-    horizontal_edge = true;
-
-  CSSParserTokenRange range_after_first_consume = range;
-  CSSValue* value2 = ConsumePositionComponent(range, context, unitless,
-                                              horizontal_edge, vertical_edge);
-  if (!value2) {
-    PositionFromOneValue(value1, result_x, result_y);
-    return true;
-  }
-
-  CSSParserTokenRange range_after_second_consume = range;
-  CSSValue* value3 = nullptr;
-  auto* identifier_value1 = DynamicTo<CSSIdentifierValue>(value1);
-  auto* identifier_value2 = DynamicTo<CSSIdentifierValue>(value2);
-  // TODO(crbug.com/940442): Fix the strange comparison of a
-  // CSSIdentifierValue instance against a specific "range peek" type check.
-  if (identifier_value1 &&
-      !!identifier_value2 != (range.Peek().GetType() == kIdentToken) &&
-      (identifier_value2
-           ? identifier_value2->GetValueID()
-           : identifier_value1->GetValueID()) != CSSValueID::kCenter) {
-    value3 = ConsumePositionComponent(range, context, unitless, horizontal_edge,
-                                      vertical_edge);
-  }
-  if (!value3) {
-    if (vertical_edge && !value2->IsIdentifierValue()) {
-      range = range_after_first_consume;
-      PositionFromOneValue(value1, result_x, result_y);
-      return true;
-    }
-    PositionFromTwoValues(value1, value2, result_x, result_y);
-    return true;
-  }
-
-  CSSValue* value4 = nullptr;
-  auto* identifier_value3 = DynamicTo<CSSIdentifierValue>(value3);
-  if (identifier_value3 &&
-      identifier_value3->GetValueID() != CSSValueID::kCenter &&
-      range.Peek().GetType() != kIdentToken) {
-    value4 = ConsumePositionComponent(range, context, unitless, horizontal_edge,
-                                      vertical_edge);
-  }
-
-  if (!value4) {
-    if (!three_value_position) {
-      // [top | bottom] <length-percentage> is not permitted
-      if (vertical_edge && !value2->IsIdentifierValue()) {
-        range = range_after_first_consume;
-        PositionFromOneValue(value1, result_x, result_y);
-        return true;
-      }
-      range = range_after_second_consume;
-      PositionFromTwoValues(value1, value2, result_x, result_y);
-      return true;
-    }
-    DCHECK_EQ(*three_value_position,
-              WebFeature::kThreeValuedPositionBackground);
-    context.Count(*three_value_position);
-  }
-
-  CSSValue* values[5];
-  values[0] = value1;
-  values[1] = value2;
-  values[2] = value3;
-  values[3] = value4;
-  values[4] = nullptr;
-  PositionFromThreeOrFourValues(values, result_x, result_y);
-  return true;
-}
-
-CSSValuePair* ConsumePosition(CSSParserTokenRange& range,
-                              const CSSParserContext& context,
-                              UnitlessQuirk unitless,
-                              base::Optional<WebFeature> three_value_position) {
-  CSSValue* result_x = nullptr;
-  CSSValue* result_y = nullptr;
-  if (ConsumePosition(range, context, unitless, three_value_position, result_x,
-                      result_y)) {
-    return MakeGarbageCollected<CSSValuePair>(
-        result_x, result_y, CSSValuePair::kKeepIdenticalValues);
-  }
-  return nullptr;
-}
-
-bool ConsumeOneOrTwoValuedPosition(CSSParserTokenRange& range,
-                                   const CSSParserContext& context,
-                                   UnitlessQuirk unitless,
-                                   CSSValue*& result_x,
-                                   CSSValue*& result_y) {
-  bool horizontal_edge = false;
-  bool vertical_edge = false;
-  CSSValue* value1 = ConsumePositionComponent(range, context, unitless,
-                                              horizontal_edge, vertical_edge);
-  if (!value1)
-    return false;
-  if (!value1->IsIdentifierValue())
-    horizontal_edge = true;
-
-  if (vertical_edge &&
-      ConsumeLengthOrPercent(range, context, kValueRangeAll, unitless)) {
-    // <length-percentage> is not permitted after top | bottom.
-    return false;
-  }
-  CSSValue* value2 = ConsumePositionComponent(range, context, unitless,
-                                              horizontal_edge, vertical_edge);
-  if (!value2) {
-    PositionFromOneValue(value1, result_x, result_y);
-    return true;
-  }
-  PositionFromTwoValues(value1, value2, result_x, result_y);
-  return true;
-}
-
-bool ConsumeBorderShorthand(CSSParserTokenRange& range,
-                            const CSSParserContext& context,
-                            const CSSValue*& result_width,
-                            const CSSValue*& result_style,
-                            const CSSValue*& result_color) {
-  while (!result_width || !result_style || !result_color) {
-    if (!result_width) {
-      result_width = css_property_parser_helpers::ConsumeLineWidth(
-          range, context, css_property_parser_helpers::UnitlessQuirk::kForbid);
-      if (result_width)
-        continue;
-    }
-    if (!result_style) {
-      result_style = css_property_parser_helpers::ParseLonghand(
-          CSSPropertyID::kBorderLeftStyle, CSSPropertyID::kBorder, context,
-          range);
-      if (result_style)
-        continue;
-    }
-    if (!result_color) {
-      result_color = css_property_parser_helpers::ConsumeColor(range, context);
-      if (result_color)
-        continue;
-    }
-    break;
-  }
-
-  if (!result_width && !result_style && !result_color)
-    return false;
-
-  if (!result_width)
-    result_width = CSSInitialValue::Create();
-  if (!result_style)
-    result_style = CSSInitialValue::Create();
-  if (!result_color)
-    result_color = CSSInitialValue::Create();
-  return true;
-}
-
-// This should go away once we drop support for -webkit-gradient
-static CSSPrimitiveValue* ConsumeDeprecatedGradientPoint(
-    CSSParserTokenRange& args,
-    const CSSParserContext& context,
-    bool horizontal) {
-  if (args.Peek().GetType() == kIdentToken) {
-    if ((horizontal && ConsumeIdent<CSSValueID::kLeft>(args)) ||
-        (!horizontal && ConsumeIdent<CSSValueID::kTop>(args)))
-      return CSSNumericLiteralValue::Create(
-          0., CSSPrimitiveValue::UnitType::kPercentage);
-    if ((horizontal && ConsumeIdent<CSSValueID::kRight>(args)) ||
-        (!horizontal && ConsumeIdent<CSSValueID::kBottom>(args)))
-      return CSSNumericLiteralValue::Create(
-          100., CSSPrimitiveValue::UnitType::kPercentage);
-    if (ConsumeIdent<CSSValueID::kCenter>(args))
-      return CSSNumericLiteralValue::Create(
-          50., CSSPrimitiveValue::UnitType::kPercentage);
-    return nullptr;
-  }
-  CSSPrimitiveValue* result = ConsumePercent(args, context, kValueRangeAll);
-  if (!result)
-    result = ConsumeNumber(args, context, kValueRangeAll);
-  return result;
-}
-
-// Used to parse colors for -webkit-gradient(...).
-static CSSValue* ConsumeDeprecatedGradientStopColor(
-    CSSParserTokenRange& args,
-    const CSSParserContext& context) {
-  if (args.Peek().Id() == CSSValueID::kCurrentcolor)
-    return nullptr;
-  return ConsumeColor(args, context);
-}
-
-static bool ConsumeDeprecatedGradientColorStop(
-    CSSParserTokenRange& range,
-    cssvalue::CSSGradientColorStop& stop,
-    const CSSParserContext& context) {
-  CSSValueID id = range.Peek().FunctionId();
-  if (id != CSSValueID::kFrom && id != CSSValueID::kTo &&
-      id != CSSValueID::kColorStop)
-    return false;
-
-  CSSParserTokenRange args = ConsumeFunction(range);
-  double position;
-  if (id == CSSValueID::kFrom || id == CSSValueID::kTo) {
-    position = (id == CSSValueID::kFrom) ? 0 : 1;
-  } else {
-    DCHECK(id == CSSValueID::kColorStop);
-    if (CSSPrimitiveValue* percent_value =
-            ConsumePercent(args, context, kValueRangeAll))
-      position = percent_value->GetDoubleValue() / 100.0;
-    else if (!ConsumeNumberRaw(args, context, position))
-      return false;
-
-    if (!ConsumeCommaIncludingWhitespace(args))
-      return false;
-  }
-
-  stop.offset_ = CSSNumericLiteralValue::Create(
-      position, CSSPrimitiveValue::UnitType::kNumber);
-  stop.color_ = ConsumeDeprecatedGradientStopColor(args, context);
-  return stop.color_ && args.AtEnd();
-}
-
-static CSSValue* ConsumeDeprecatedGradient(CSSParserTokenRange& args,
-                                           const CSSParserContext& context) {
-  CSSValueID id = args.ConsumeIncludingWhitespace().Id();
-  if (id != CSSValueID::kRadial && id != CSSValueID::kLinear)
-    return nullptr;
-
-  if (!ConsumeCommaIncludingWhitespace(args))
-    return nullptr;
-
-  const CSSPrimitiveValue* first_x =
-      ConsumeDeprecatedGradientPoint(args, context, true);
-  if (!first_x)
-    return nullptr;
-  const CSSPrimitiveValue* first_y =
-      ConsumeDeprecatedGradientPoint(args, context, false);
-  if (!first_y)
-    return nullptr;
-  if (!ConsumeCommaIncludingWhitespace(args))
-    return nullptr;
-
-  // For radial gradients only, we now expect a numeric radius.
-  const CSSPrimitiveValue* first_radius = nullptr;
-  if (id == CSSValueID::kRadial) {
-    first_radius = ConsumeNumber(args, context, kValueRangeNonNegative);
-    if (!first_radius || !ConsumeCommaIncludingWhitespace(args))
-      return nullptr;
-  }
-
-  const CSSPrimitiveValue* second_x =
-      ConsumeDeprecatedGradientPoint(args, context, true);
-  if (!second_x)
-    return nullptr;
-  const CSSPrimitiveValue* second_y =
-      ConsumeDeprecatedGradientPoint(args, context, false);
-  if (!second_y)
-    return nullptr;
-
-  // For radial gradients only, we now expect the second radius.
-  const CSSPrimitiveValue* second_radius = nullptr;
-  if (id == CSSValueID::kRadial) {
-    if (!ConsumeCommaIncludingWhitespace(args))
-      return nullptr;
-    second_radius = ConsumeNumber(args, context, kValueRangeNonNegative);
-    if (!second_radius)
-      return nullptr;
-  }
-
-  cssvalue::CSSGradientValue* result;
-  if (id == CSSValueID::kRadial) {
-    result = MakeGarbageCollected<cssvalue::CSSRadialGradientValue>(
-        first_x, first_y, first_radius, second_x, second_y, second_radius,
-        cssvalue::kNonRepeating, cssvalue::kCSSDeprecatedRadialGradient);
-  } else {
-    result = MakeGarbageCollected<cssvalue::CSSLinearGradientValue>(
-        first_x, first_y, second_x, second_y, nullptr, cssvalue::kNonRepeating,
-        cssvalue::kCSSDeprecatedLinearGradient);
-  }
-  cssvalue::CSSGradientColorStop stop;
-  while (ConsumeCommaIncludingWhitespace(args)) {
-    if (!ConsumeDeprecatedGradientColorStop(args, stop, context))
-      return nullptr;
-    result->AddStop(stop);
-  }
-
-  return result;
-}
-
-static CSSPrimitiveValue* ConsumeGradientAngleOrPercent(
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    ValueRange value_range,
-    UnitlessQuirk) {
-  const CSSParserToken& token = range.Peek();
-  if (token.GetType() == kDimensionToken || token.GetType() == kNumberToken) {
-    return ConsumeAngle(range, context, WebFeature::kUnitlessZeroAngleGradient);
-  }
-  if (token.GetType() == kPercentageToken)
-    return ConsumePercent(range, context, value_range);
-  MathFunctionParser math_parser(range, context, value_range);
-  if (const CSSMathFunctionValue* calculation = math_parser.Value()) {
-    CalculationCategory category = calculation->Category();
-    // TODO(fs): Add and support kCalcPercentAngle?
-    if (category == kCalcAngle || category == kCalcPercent)
-      return math_parser.ConsumeValue();
-  }
-  return nullptr;
-}
-
-using PositionFunctor = CSSPrimitiveValue* (*)(CSSParserTokenRange&,
-                                               const CSSParserContext&,
-                                               ValueRange,
-                                               UnitlessQuirk);
-
-static bool ConsumeGradientColorStops(CSSParserTokenRange& range,
-                                      const CSSParserContext& context,
-                                      cssvalue::CSSGradientValue* gradient,
-                                      PositionFunctor consume_position_func) {
-  bool supports_color_hints =
-      gradient->GradientType() == cssvalue::kCSSLinearGradient ||
-      gradient->GradientType() == cssvalue::kCSSRadialGradient ||
-      gradient->GradientType() == cssvalue::kCSSConicGradient;
-
-  // The first color stop cannot be a color hint.
-  bool previous_stop_was_color_hint = true;
-  do {
-    cssvalue::CSSGradientColorStop stop;
-    stop.color_ = ConsumeColor(range, context);
-    // Two hints in a row are not allowed.
-    if (!stop.color_ && (!supports_color_hints || previous_stop_was_color_hint))
-      return false;
-    previous_stop_was_color_hint = !stop.color_;
-    stop.offset_ = consume_position_func(range, context, kValueRangeAll,
-                                         UnitlessQuirk::kForbid);
-    if (!stop.color_ && !stop.offset_)
-      return false;
-    gradient->AddStop(stop);
-
-    if (!stop.color_ || !stop.offset_)
-      continue;
-
-    // Optional second position.
-    stop.offset_ = consume_position_func(range, context, kValueRangeAll,
-                                         UnitlessQuirk::kForbid);
-    if (stop.offset_)
-      gradient->AddStop(stop);
-  } while (ConsumeCommaIncludingWhitespace(range));
-
-  // The last color stop cannot be a color hint.
-  if (previous_stop_was_color_hint)
-    return false;
-
-  // Must have 2 or more stops to be valid.
-  return gradient->StopCount() >= 2;
-}
-
-static CSSValue* ConsumeDeprecatedRadialGradient(
-    CSSParserTokenRange& args,
-    const CSSParserContext& context,
-    cssvalue::CSSGradientRepeat repeating) {
-  CSSValue* center_x = nullptr;
-  CSSValue* center_y = nullptr;
-  ConsumeOneOrTwoValuedPosition(args, context, UnitlessQuirk::kForbid, center_x,
-                                center_y);
-  if ((center_x || center_y) && !ConsumeCommaIncludingWhitespace(args))
-    return nullptr;
-
-  const CSSIdentifierValue* shape =
-      ConsumeIdent<CSSValueID::kCircle, CSSValueID::kEllipse>(args);
-  const CSSIdentifierValue* size_keyword =
-      ConsumeIdent<CSSValueID::kClosestSide, CSSValueID::kClosestCorner,
-                   CSSValueID::kFarthestSide, CSSValueID::kFarthestCorner,
-                   CSSValueID::kContain, CSSValueID::kCover>(args);
-  if (!shape)
-    shape = ConsumeIdent<CSSValueID::kCircle, CSSValueID::kEllipse>(args);
-
-  // Or, two lengths or percentages
-  const CSSPrimitiveValue* horizontal_size = nullptr;
-  const CSSPrimitiveValue* vertical_size = nullptr;
-  if (!shape && !size_keyword) {
-    horizontal_size =
-        ConsumeLengthOrPercent(args, context, kValueRangeNonNegative);
-    if (horizontal_size) {
-      vertical_size =
-          ConsumeLengthOrPercent(args, context, kValueRangeNonNegative);
-      if (!vertical_size)
-        return nullptr;
-      ConsumeCommaIncludingWhitespace(args);
-    }
-  } else {
-    ConsumeCommaIncludingWhitespace(args);
-  }
-
-  cssvalue::CSSGradientValue* result =
-      MakeGarbageCollected<cssvalue::CSSRadialGradientValue>(
-          center_x, center_y, shape, size_keyword, horizontal_size,
-          vertical_size, repeating, cssvalue::kCSSPrefixedRadialGradient);
-  return ConsumeGradientColorStops(args, context, result,
-                                   ConsumeGradientLengthOrPercent)
-             ? result
-             : nullptr;
-}
-
-static CSSValue* ConsumeRadialGradient(CSSParserTokenRange& args,
-                                       const CSSParserContext& context,
-                                       cssvalue::CSSGradientRepeat repeating) {
-  const CSSIdentifierValue* shape = nullptr;
-  const CSSIdentifierValue* size_keyword = nullptr;
-  const CSSPrimitiveValue* horizontal_size = nullptr;
-  const CSSPrimitiveValue* vertical_size = nullptr;
-
-  // First part of grammar, the size/shape clause:
-  // [ circle || <length> ] |
-  // [ ellipse || [ <length> | <percentage> ]{2} ] |
-  // [ [ circle | ellipse] || <size-keyword> ]
-  for (int i = 0; i < 3; ++i) {
-    if (args.Peek().GetType() == kIdentToken) {
-      CSSValueID id = args.Peek().Id();
-      if (id == CSSValueID::kCircle || id == CSSValueID::kEllipse) {
-        if (shape)
-          return nullptr;
-        shape = ConsumeIdent(args);
-      } else if (id == CSSValueID::kClosestSide ||
-                 id == CSSValueID::kClosestCorner ||
-                 id == CSSValueID::kFarthestSide ||
-                 id == CSSValueID::kFarthestCorner) {
-        if (size_keyword)
-          return nullptr;
-        size_keyword = ConsumeIdent(args);
-      } else {
-        break;
-      }
-    } else {
-      CSSPrimitiveValue* center =
-          ConsumeLengthOrPercent(args, context, kValueRangeNonNegative);
-      if (!center)
-        break;
-      if (horizontal_size)
-        return nullptr;
-      horizontal_size = center;
-      center = ConsumeLengthOrPercent(args, context, kValueRangeNonNegative);
-      if (center) {
-        vertical_size = center;
-        ++i;
-      }
-    }
-  }
-
-  // You can specify size as a keyword or a length/percentage, not both.
-  if (size_keyword && horizontal_size)
-    return nullptr;
-  // Circles must have 0 or 1 lengths.
-  if (shape && shape->GetValueID() == CSSValueID::kCircle && vertical_size)
-    return nullptr;
-  // Ellipses must have 0 or 2 length/percentages.
-  if (shape && shape->GetValueID() == CSSValueID::kEllipse && horizontal_size &&
-      !vertical_size) {
-    return nullptr;
-  }
-  // If there's only one size, it must be a length.
-  if (!vertical_size && horizontal_size && horizontal_size->IsPercentage())
-    return nullptr;
-  if ((horizontal_size &&
-       horizontal_size->IsCalculatedPercentageWithLength()) ||
-      (vertical_size && vertical_size->IsCalculatedPercentageWithLength())) {
-    return nullptr;
-  }
-
-  CSSValue* center_x = nullptr;
-  CSSValue* center_y = nullptr;
-  if (args.Peek().Id() == CSSValueID::kAt) {
-    args.ConsumeIncludingWhitespace();
-    ConsumePosition(args, context, UnitlessQuirk::kForbid,
-                    base::Optional<WebFeature>(), center_x, center_y);
-    if (!(center_x && center_y))
-      return nullptr;
-    // Right now, CSS radial gradients have the same start and end centers.
-  }
-
-  if ((shape || size_keyword || horizontal_size || center_x || center_y) &&
-      !ConsumeCommaIncludingWhitespace(args)) {
-    return nullptr;
-  }
-
-  cssvalue::CSSGradientValue* result =
-      MakeGarbageCollected<cssvalue::CSSRadialGradientValue>(
-          center_x, center_y, shape, size_keyword, horizontal_size,
-          vertical_size, repeating, cssvalue::kCSSRadialGradient);
-  return ConsumeGradientColorStops(args, context, result,
-                                   ConsumeGradientLengthOrPercent)
-             ? result
-             : nullptr;
-}
-
-static CSSValue* ConsumeLinearGradient(
-    CSSParserTokenRange& args,
-    const CSSParserContext& context,
-    cssvalue::CSSGradientRepeat repeating,
-    cssvalue::CSSGradientType gradient_type) {
-  bool expect_comma = true;
-  const CSSPrimitiveValue* angle =
-      ConsumeAngle(args, context, WebFeature::kUnitlessZeroAngleGradient);
-  const CSSIdentifierValue* end_x = nullptr;
-  const CSSIdentifierValue* end_y = nullptr;
-  if (!angle) {
-    if (gradient_type == cssvalue::kCSSPrefixedLinearGradient ||
-        ConsumeIdent<CSSValueID::kTo>(args)) {
-      end_x = ConsumeIdent<CSSValueID::kLeft, CSSValueID::kRight>(args);
-      end_y = ConsumeIdent<CSSValueID::kBottom, CSSValueID::kTop>(args);
-      if (!end_x && !end_y) {
-        if (gradient_type == cssvalue::kCSSLinearGradient)
-          return nullptr;
-        end_y = CSSIdentifierValue::Create(CSSValueID::kTop);
-        expect_comma = false;
-      } else if (!end_x) {
-        end_x = ConsumeIdent<CSSValueID::kLeft, CSSValueID::kRight>(args);
-      }
-    } else {
-      expect_comma = false;
-    }
-  }
-
-  if (expect_comma && !ConsumeCommaIncludingWhitespace(args))
-    return nullptr;
-
-  cssvalue::CSSGradientValue* result =
-      MakeGarbageCollected<cssvalue::CSSLinearGradientValue>(
-          end_x, end_y, nullptr, nullptr, angle, repeating, gradient_type);
-  return ConsumeGradientColorStops(args, context, result,
-                                   ConsumeGradientLengthOrPercent)
-             ? result
-             : nullptr;
-}
-
-static CSSValue* ConsumeConicGradient(CSSParserTokenRange& args,
-                                      const CSSParserContext& context,
-                                      cssvalue::CSSGradientRepeat repeating) {
-  const CSSPrimitiveValue* from_angle = nullptr;
-  if (ConsumeIdent<CSSValueID::kFrom>(args)) {
-    if (!(from_angle = ConsumeAngle(args, context,
-                                    WebFeature::kUnitlessZeroAngleGradient)))
-      return nullptr;
-  }
-
-  CSSValue* center_x = nullptr;
-  CSSValue* center_y = nullptr;
-  if (ConsumeIdent<CSSValueID::kAt>(args)) {
-    if (!ConsumePosition(args, context, UnitlessQuirk::kForbid,
-                         base::Optional<WebFeature>(), center_x, center_y))
-      return nullptr;
-  }
-
-  // Comma separator required when fromAngle or position is present.
-  if ((from_angle || center_x || center_y) &&
-      !ConsumeCommaIncludingWhitespace(args)) {
-    return nullptr;
-  }
-
-  auto* result = MakeGarbageCollected<cssvalue::CSSConicGradientValue>(
-      center_x, center_y, from_angle, repeating);
-  return ConsumeGradientColorStops(args, context, result,
-                                   ConsumeGradientAngleOrPercent)
-             ? result
-             : nullptr;
-}
-
-CSSValue* ConsumeImageOrNone(CSSParserTokenRange& range,
-                             const CSSParserContext& context) {
-  if (range.Peek().Id() == CSSValueID::kNone)
-    return ConsumeIdent(range);
-  return ConsumeImage(range, context);
-}
-
-CSSValue* ConsumeAxis(CSSParserTokenRange& range,
-                      const CSSParserContext& context) {
-  CSSValueID axis_id = range.Peek().Id();
-  if (axis_id == CSSValueID::kX || axis_id == CSSValueID::kY ||
-      axis_id == CSSValueID::kZ) {
-    ConsumeIdent(range);
-    return MakeGarbageCollected<cssvalue::CSSAxisValue>(axis_id);
-  }
-
-  CSSValue* x_dimension = css_property_parser_helpers::ConsumeNumber(
-      range, context, kValueRangeAll);
-  CSSValue* y_dimension = css_property_parser_helpers::ConsumeNumber(
-      range, context, kValueRangeAll);
-  CSSValue* z_dimension = css_property_parser_helpers::ConsumeNumber(
-      range, context, kValueRangeAll);
-  if (!x_dimension || !y_dimension || !z_dimension)
-    return nullptr;
-  double x = To<CSSPrimitiveValue>(x_dimension)->GetDoubleValue();
-  double y = To<CSSPrimitiveValue>(y_dimension)->GetDoubleValue();
-  double z = To<CSSPrimitiveValue>(z_dimension)->GetDoubleValue();
-  return MakeGarbageCollected<cssvalue::CSSAxisValue>(x, y, z);
-}
-
-static CSSValue* ConsumeCrossFade(CSSParserTokenRange& args,
-                                  const CSSParserContext& context) {
-  CSSValue* from_image_value = ConsumeImageOrNone(args, context);
-  if (!from_image_value || !ConsumeCommaIncludingWhitespace(args))
-    return nullptr;
-  CSSValue* to_image_value = ConsumeImageOrNone(args, context);
-  if (!to_image_value || !ConsumeCommaIncludingWhitespace(args))
-    return nullptr;
-
-  CSSPrimitiveValue* percentage = nullptr;
-  if (CSSPrimitiveValue* percent_value =
-          ConsumePercent(args, context, kValueRangeAll))
-    percentage = CSSNumericLiteralValue::Create(
-        clampTo<double>(percent_value->GetDoubleValue() / 100.0, 0, 1),
-        CSSPrimitiveValue::UnitType::kNumber);
-  else if (CSSPrimitiveValue* number_value =
-               ConsumeNumber(args, context, kValueRangeAll))
-    percentage = CSSNumericLiteralValue::Create(
-        clampTo<double>(number_value->GetDoubleValue(), 0, 1),
-        CSSPrimitiveValue::UnitType::kNumber);
-
-  if (!percentage)
-    return nullptr;
-  return MakeGarbageCollected<cssvalue::CSSCrossfadeValue>(
-      from_image_value, to_image_value, percentage);
-}
-
-static CSSValue* ConsumePaint(CSSParserTokenRange& args,
-                              const CSSParserContext& context) {
-  const CSSParserToken& name_token = args.ConsumeIncludingWhitespace();
-  CSSCustomIdentValue* name = ConsumeCustomIdentWithToken(name_token, context);
-  if (!name)
-    return nullptr;
-
-  if (args.AtEnd())
-    return MakeGarbageCollected<CSSPaintValue>(name);
-
-  if (!RuntimeEnabledFeatures::CSSPaintAPIArgumentsEnabled()) {
-    // Arguments not enabled, but exists. Invalid.
-    return nullptr;
-  }
-
-  // Begin parse paint arguments.
-  if (!ConsumeCommaIncludingWhitespace(args))
-    return nullptr;
-
-  // Consume arguments.
-  // TODO(renjieliu): We may want to optimize the implementation by resolve
-  // variables early if paint function is registered.
-  Vector<CSSParserToken> argument_tokens;
-  Vector<scoped_refptr<CSSVariableData>> variable_data;
-  while (!args.AtEnd()) {
-    if (args.Peek().GetType() != kCommaToken) {
-      argument_tokens.AppendVector(ConsumeFunctionArgsOrNot(args));
-    } else {
-      if (!AddCSSPaintArgument(argument_tokens, &variable_data, context))
-        return nullptr;
-      argument_tokens.clear();
-      if (!ConsumeCommaIncludingWhitespace(args))
-        return nullptr;
-    }
-  }
-  if (!AddCSSPaintArgument(argument_tokens, &variable_data, context))
-    return nullptr;
-
-  return MakeGarbageCollected<CSSPaintValue>(name, variable_data);
-}
-
-static CSSValue* ConsumeGeneratedImage(CSSParserTokenRange& range,
-                                       const CSSParserContext& context) {
-  CSSValueID id = range.Peek().FunctionId();
-  CSSParserTokenRange range_copy = range;
-  CSSParserTokenRange args = ConsumeFunction(range_copy);
-  CSSValue* result = nullptr;
-  if (id == CSSValueID::kRadialGradient) {
-    result = ConsumeRadialGradient(args, context, cssvalue::kNonRepeating);
-  } else if (id == CSSValueID::kRepeatingRadialGradient) {
-    result = ConsumeRadialGradient(args, context, cssvalue::kRepeating);
-  } else if (id == CSSValueID::kWebkitLinearGradient) {
-    context.Count(WebFeature::kDeprecatedWebKitLinearGradient);
-    result = ConsumeLinearGradient(args, context, cssvalue::kNonRepeating,
-                                   cssvalue::kCSSPrefixedLinearGradient);
-  } else if (id == CSSValueID::kWebkitRepeatingLinearGradient) {
-    context.Count(WebFeature::kDeprecatedWebKitRepeatingLinearGradient);
-    result = ConsumeLinearGradient(args, context, cssvalue::kRepeating,
-                                   cssvalue::kCSSPrefixedLinearGradient);
-  } else if (id == CSSValueID::kRepeatingLinearGradient) {
-    result = ConsumeLinearGradient(args, context, cssvalue::kRepeating,
-                                   cssvalue::kCSSLinearGradient);
-  } else if (id == CSSValueID::kLinearGradient) {
-    result = ConsumeLinearGradient(args, context, cssvalue::kNonRepeating,
-                                   cssvalue::kCSSLinearGradient);
-  } else if (id == CSSValueID::kWebkitGradient) {
-    context.Count(WebFeature::kDeprecatedWebKitGradient);
-    result = ConsumeDeprecatedGradient(args, context);
-  } else if (id == CSSValueID::kWebkitRadialGradient) {
-    context.Count(WebFeature::kDeprecatedWebKitRadialGradient);
-    result =
-        ConsumeDeprecatedRadialGradient(args, context, cssvalue::kNonRepeating);
-  } else if (id == CSSValueID::kWebkitRepeatingRadialGradient) {
-    context.Count(WebFeature::kDeprecatedWebKitRepeatingRadialGradient);
-    result =
-        ConsumeDeprecatedRadialGradient(args, context, cssvalue::kRepeating);
-  } else if (id == CSSValueID::kConicGradient) {
-    result = ConsumeConicGradient(args, context, cssvalue::kNonRepeating);
-  } else if (id == CSSValueID::kRepeatingConicGradient) {
-    result = ConsumeConicGradient(args, context, cssvalue::kRepeating);
-  } else if (id == CSSValueID::kWebkitCrossFade) {
-    result = ConsumeCrossFade(args, context);
-  } else if (id == CSSValueID::kPaint) {
-    result = context.IsSecureContext() ? ConsumePaint(args, context) : nullptr;
-  }
-  if (!result || !args.AtEnd())
-    return nullptr;
-
-  WebFeature feature;
-  if (id == CSSValueID::kWebkitCrossFade)
-    feature = WebFeature::kWebkitCrossFade;
-  else if (id == CSSValueID::kPaint)
-    feature = WebFeature::kCSSPaintFunction;
-  else
-    feature = WebFeature::kCSSGradient;
-  context.Count(feature);
-
-  range = range_copy;
-  return result;
-}
-
-static CSSValue* CreateCSSImageValueWithReferrer(
-    const AtomicString& raw_value,
-    const CSSParserContext& context) {
-  CSSValue* image_value = MakeGarbageCollected<CSSImageValue>(
-      raw_value, context.CompleteURL(raw_value), context.GetReferrer(),
-      context.IsOriginClean() ? OriginClean::kTrue : OriginClean::kFalse,
-      context.IsAdRelated());
-  return image_value;
-}
-
-static CSSValue* ConsumeImageSet(CSSParserTokenRange& range,
-                                 const CSSParserContext& context) {
-  CSSParserTokenRange range_copy = range;
-  CSSParserTokenRange args = ConsumeFunction(range_copy);
-  auto* image_set = MakeGarbageCollected<CSSImageSetValue>(context.Mode());
-  do {
-    AtomicString url_value =
-        ConsumeUrlAsStringView(args, context).ToAtomicString();
-    if (url_value.IsNull())
-      return nullptr;
-
-    CSSValue* image = CreateCSSImageValueWithReferrer(url_value, context);
-    image_set->Append(*image);
-
-    const CSSParserToken& token = args.ConsumeIncludingWhitespace();
-    if (token.GetType() != kDimensionToken)
-      return nullptr;
-    if (token.Value() != "x")
-      return nullptr;
-    DCHECK(token.GetUnitType() == CSSPrimitiveValue::UnitType::kDotsPerPixel);
-    double image_scale_factor = token.NumericValue();
-    if (image_scale_factor <= 0)
-      return nullptr;
-    image_set->Append(*CSSNumericLiteralValue::Create(
-        image_scale_factor, CSSPrimitiveValue::UnitType::kNumber));
-  } while (ConsumeCommaIncludingWhitespace(args));
-  if (!args.AtEnd())
-    return nullptr;
-  range = range_copy;
-  return image_set;
-}
-
-static bool IsGeneratedImage(CSSValueID id) {
-  return id == CSSValueID::kLinearGradient ||
-         id == CSSValueID::kRadialGradient ||
-         id == CSSValueID::kConicGradient ||
-         id == CSSValueID::kRepeatingLinearGradient ||
-         id == CSSValueID::kRepeatingRadialGradient ||
-         id == CSSValueID::kRepeatingConicGradient ||
-         id == CSSValueID::kWebkitLinearGradient ||
-         id == CSSValueID::kWebkitRadialGradient ||
-         id == CSSValueID::kWebkitRepeatingLinearGradient ||
-         id == CSSValueID::kWebkitRepeatingRadialGradient ||
-         id == CSSValueID::kWebkitGradient ||
-         id == CSSValueID::kWebkitCrossFade || id == CSSValueID::kPaint;
-}
-
-CSSValue* ConsumeImage(CSSParserTokenRange& range,
-                       const CSSParserContext& context,
-                       ConsumeGeneratedImagePolicy generated_image) {
-  AtomicString uri = ConsumeUrlAsStringView(range, context).ToAtomicString();
-  if (!uri.IsNull())
-    return CreateCSSImageValueWithReferrer(uri, context);
-  if (range.Peek().GetType() == kFunctionToken) {
-    CSSValueID id = range.Peek().FunctionId();
-    if (id == CSSValueID::kWebkitImageSet)
-      return ConsumeImageSet(range, context);
-    if (generated_image == ConsumeGeneratedImagePolicy::kAllow &&
-        IsGeneratedImage(id)) {
-      return ConsumeGeneratedImage(range, context);
-    }
-    return ConsumeInternalLightDark(ConsumeImageOrNone, range, context);
-  }
-  return nullptr;
-}
-
-// https://drafts.csswg.org/css-values-4/#css-wide-keywords
-bool IsCSSWideKeyword(StringView keyword) {
-  return EqualIgnoringASCIICase(keyword, "initial") ||
-         EqualIgnoringASCIICase(keyword, "inherit") ||
-         EqualIgnoringASCIICase(keyword, "unset") ||
-         (RuntimeEnabledFeatures::CSSRevertEnabled() &&
-          EqualIgnoringASCIICase(keyword, "revert"));
-}
-
-// https://drafts.csswg.org/css-cascade/#default
-bool IsRevertKeyword(StringView keyword) {
-  return EqualIgnoringASCIICase(keyword, "revert");
-}
-
-// https://drafts.csswg.org/css-values-4/#identifier-value
-bool IsDefaultKeyword(StringView keyword) {
-  return EqualIgnoringASCIICase(keyword, "default");
-}
-
-// https://drafts.csswg.org/css-shapes-1/#typedef-shape-box
-CSSIdentifierValue* ConsumeShapeBox(CSSParserTokenRange& range) {
-  return ConsumeIdent<CSSValueID::kContentBox, CSSValueID::kPaddingBox,
-                      CSSValueID::kBorderBox, CSSValueID::kMarginBox>(range);
-}
-
-void AddProperty(CSSPropertyID resolved_property,
-                 CSSPropertyID current_shorthand,
-                 const CSSValue& value,
-                 bool important,
-                 IsImplicitProperty implicit,
-                 HeapVector<CSSPropertyValue, 256>& properties) {
-  DCHECK(!isPropertyAlias(resolved_property));
-  DCHECK(implicit == IsImplicitProperty::kNotImplicit ||
-         implicit == IsImplicitProperty::kImplicit);
-
-  int shorthand_index = 0;
-  bool set_from_shorthand = false;
-
-  if (isValidCSSPropertyID(current_shorthand)) {
-    Vector<StylePropertyShorthand, 4> shorthands;
-    getMatchingShorthandsForLonghand(resolved_property, &shorthands);
-    set_from_shorthand = true;
-    if (shorthands.size() > 1) {
-      shorthand_index =
-          indexOfShorthandForLonghand(current_shorthand, shorthands);
-    }
-  }
-
-  properties.push_back(CSSPropertyValue(
-      CSSProperty::Get(resolved_property), value, important, set_from_shorthand,
-      shorthand_index, implicit == IsImplicitProperty::kImplicit));
-}
-
-CSSValue* ConsumeTransformValue(CSSParserTokenRange& range,
-                                const CSSParserContext& context) {
-  bool use_legacy_parsing = false;
-  return css_parsing_utils::ConsumeTransformValue(range, context,
-                                                  use_legacy_parsing);
-}
-
-CSSValue* ConsumeTransformList(CSSParserTokenRange& range,
-                               const CSSParserContext& context) {
-  return css_parsing_utils::ConsumeTransformList(range, context,
-                                                 CSSParserLocalContext());
-}
-
-CSSValue* ConsumeFilterFunctionList(CSSParserTokenRange& range,
-                                    const CSSParserContext& context) {
-  if (range.Peek().Id() == CSSValueID::kNone)
-    return ConsumeIdent(range);
-
-  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
-  do {
-    CSSValue* filter_value = ConsumeUrl(range, context);
-    if (!filter_value) {
-      filter_value = ConsumeFilterFunction(range, context);
-      if (!filter_value)
-        return nullptr;
-    }
-    list->Append(*filter_value);
-  } while (!range.AtEnd());
-  return list;
-}
-
-void CountKeywordOnlyPropertyUsage(CSSPropertyID property,
-                                   const CSSParserContext& context,
-                                   CSSValueID value_id) {
-  if (!context.IsUseCounterRecordingEnabled())
-    return;
-  switch (property) {
-    case CSSPropertyID::kAppearance:
-      if (value_id == CSSValueID::kInnerSpinButton ||
-          value_id == CSSValueID::kMediaSlider ||
-          value_id == CSSValueID::kMediaSliderthumb ||
-          value_id == CSSValueID::kMediaVolumeSlider ||
-          value_id == CSSValueID::kMediaVolumeSliderthumb ||
-          value_id == CSSValueID::kSliderVertical ||
-          value_id == CSSValueID::kSliderthumbHorizontal ||
-          value_id == CSSValueID::kSliderthumbVertical ||
-          value_id == CSSValueID::kSearchfieldCancelButton) {
-        if (const auto* document = context.GetDocument()) {
-          document->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
-              mojom::blink::ConsoleMessageSource::kOther,
-              mojom::blink::ConsoleMessageLevel::kWarning,
-              String("The keyword '") + getValueName(value_id) +
-                  "' specified to an 'appearance' property is not "
-                  "standardized. It will be removed in the future."));
-        }
-      }
-      FALLTHROUGH;
-      // This function distinguishes 'appearance' and '-webkit-appearance'
-      // though other property aliases are handles as their aliased properties.
-      // See Appearance::ParseSingleValue().
-    case CSSPropertyID::kAliasWebkitAppearance: {
-      WebFeature feature;
-      if (value_id == CSSValueID::kNone) {
-        feature = WebFeature::kCSSValueAppearanceNone;
-      } else {
-        feature = WebFeature::kCSSValueAppearanceNotNone;
-        if (value_id == CSSValueID::kButton)
-          feature = WebFeature::kCSSValueAppearanceButton;
-        else if (value_id == CSSValueID::kCheckbox)
-          feature = WebFeature::kCSSValueAppearanceCheckbox;
-        else if (value_id == CSSValueID::kInnerSpinButton)
-          feature = WebFeature::kCSSValueAppearanceInnerSpinButton;
-        else if (value_id == CSSValueID::kMenulist)
-          feature = WebFeature::kCSSValueAppearanceMenulist;
-        else if (value_id == CSSValueID::kMenulistButton)
-          feature = WebFeature::kCSSValueAppearanceMenulistButton;
-        else if (value_id == CSSValueID::kMeter)
-          feature = WebFeature::kCSSValueAppearanceMeter;
-        else if (value_id == CSSValueID::kListbox)
-          feature = WebFeature::kCSSValueAppearanceListbox;
-        else if (value_id == CSSValueID::kProgressBar)
-          feature = WebFeature::kCSSValueAppearanceProgressBar;
-        else if (value_id == CSSValueID::kPushButton)
-          feature = WebFeature::kCSSValueAppearancePushButton;
-        else if (value_id == CSSValueID::kRadio)
-          feature = WebFeature::kCSSValueAppearanceRadio;
-        else if (value_id == CSSValueID::kSearchfieldCancelButton)
-          feature = WebFeature::kCSSValueAppearanceSearchCancel;
-        else if (value_id == CSSValueID::kSquareButton)
-          feature = WebFeature::kCSSValueAppearanceSquareButton;
-        else if (value_id == CSSValueID::kSearchfield)
-          feature = WebFeature::kCSSValueAppearanceSearchField;
-        else if (value_id == CSSValueID::kTextarea)
-          feature = WebFeature::kCSSValueAppearanceTextarea;
-        else if (value_id == CSSValueID::kTextfield)
-          feature = WebFeature::kCSSValueAppearanceTextField;
-        else
-          feature = WebFeature::kCSSValueAppearanceOthers;
-      }
-      context.Count(feature);
-      break;
-    }
-
-    case CSSPropertyID::kWebkitUserModify: {
-      switch (value_id) {
-        case CSSValueID::kReadOnly:
-          context.Count(WebFeature::kCSSValueUserModifyReadOnly);
-          break;
-        case CSSValueID::kReadWrite:
-          context.Count(WebFeature::kCSSValueUserModifyReadWrite);
-          break;
-        case CSSValueID::kReadWritePlaintextOnly:
-          context.Count(WebFeature::kCSSValueUserModifyReadWritePlaintextOnly);
-          break;
-        default:
-          NOTREACHED();
-      }
-      break;
-    }
-    case CSSPropertyID::kDisplay:
-      if (value_id == CSSValueID::kContents)
-        context.Count(WebFeature::kCSSValueDisplayContents);
-      break;
-    case CSSPropertyID::kOverflowX:
-    case CSSPropertyID::kOverflowY:
-      if (value_id == CSSValueID::kOverlay)
-        context.Count(WebFeature::kCSSValueOverflowOverlay);
-      break;
-    default:
-      break;
-  }
-}
-
-const CSSValue* ParseLonghand(CSSPropertyID unresolved_property,
-                              CSSPropertyID current_shorthand,
-                              const CSSParserContext& context,
-                              CSSParserTokenRange& range) {
-  CSSPropertyID property_id = resolveCSSPropertyID(unresolved_property);
-  DCHECK(!CSSProperty::Get(property_id).IsShorthand());
-  if (CSSParserFastPaths::IsKeywordPropertyID(property_id)) {
-    if (CSSParserFastPaths::IsValidKeywordPropertyAndValue(
-            property_id, range.Peek().Id(), context.Mode())) {
-      CountKeywordOnlyPropertyUsage(property_id, context, range.Peek().Id());
-      return ConsumeIdent(range);
-    }
-
-    // Some properties need to fallback onto the regular parser.
-    if (!CSSParserFastPaths::IsPartialKeywordPropertyID(property_id))
-      return nullptr;
-  }
-
-  const auto local_context =
-      CSSParserLocalContext()
-          .WithAliasParsing(isPropertyAlias(unresolved_property))
-          .WithCurrentShorthand(current_shorthand);
-
-  const CSSValue* result = To<Longhand>(CSSProperty::Get(property_id))
-                               .ParseSingleValue(range, context, local_context);
-  return result;
-}
-
-bool ConsumeShorthandVia2Longhands(
-    const StylePropertyShorthand& shorthand,
-    bool important,
-    const CSSParserContext& context,
-    CSSParserTokenRange& range,
-    HeapVector<CSSPropertyValue, 256>& properties) {
-  DCHECK_EQ(shorthand.length(), 2u);
-  const CSSProperty** longhands = shorthand.properties();
-
-  const CSSValue* start =
-      ParseLonghand(longhands[0]->PropertyID(), shorthand.id(), context, range);
-
-  if (!start)
-    return false;
-
-  const CSSValue* end =
-      ParseLonghand(longhands[1]->PropertyID(), shorthand.id(), context, range);
-
-  if (shorthand.id() == CSSPropertyID::kOverflow && start && end) {
-    context.Count(WebFeature::kTwoValuedOverflow);
-  }
-
-  if (!end)
-    end = start;
-  AddProperty(longhands[0]->PropertyID(), shorthand.id(), *start, important,
-              IsImplicitProperty::kNotImplicit, properties);
-  AddProperty(longhands[1]->PropertyID(), shorthand.id(), *end, important,
-              IsImplicitProperty::kNotImplicit, properties);
-
-  return range.AtEnd();
-}
-
-bool ConsumeShorthandVia4Longhands(
-    const StylePropertyShorthand& shorthand,
-    bool important,
-    const CSSParserContext& context,
-    CSSParserTokenRange& range,
-    HeapVector<CSSPropertyValue, 256>& properties) {
-  DCHECK_EQ(shorthand.length(), 4u);
-  const CSSProperty** longhands = shorthand.properties();
-  const CSSValue* top =
-      ParseLonghand(longhands[0]->PropertyID(), shorthand.id(), context, range);
-
-  if (!top)
-    return false;
-
-  const CSSValue* right =
-      ParseLonghand(longhands[1]->PropertyID(), shorthand.id(), context, range);
-
-  const CSSValue* bottom = nullptr;
-  const CSSValue* left = nullptr;
-  if (right) {
-    bottom = ParseLonghand(longhands[2]->PropertyID(), shorthand.id(), context,
-                           range);
-    if (bottom) {
-      left = ParseLonghand(longhands[3]->PropertyID(), shorthand.id(), context,
-                           range);
-    }
-  }
-
-  if (!right)
-    right = top;
-  if (!bottom)
-    bottom = top;
-  if (!left)
-    left = right;
-
-  AddProperty(longhands[0]->PropertyID(), shorthand.id(), *top, important,
-              IsImplicitProperty::kNotImplicit, properties);
-  AddProperty(longhands[1]->PropertyID(), shorthand.id(), *right, important,
-              IsImplicitProperty::kNotImplicit, properties);
-  AddProperty(longhands[2]->PropertyID(), shorthand.id(), *bottom, important,
-              IsImplicitProperty::kNotImplicit, properties);
-  AddProperty(longhands[3]->PropertyID(), shorthand.id(), *left, important,
-              IsImplicitProperty::kNotImplicit, properties);
-
-  return range.AtEnd();
-}
-
-bool ConsumeShorthandGreedilyViaLonghands(
-    const StylePropertyShorthand& shorthand,
-    bool important,
-    const CSSParserContext& context,
-    CSSParserTokenRange& range,
-    HeapVector<CSSPropertyValue, 256>& properties) {
-  // Existing shorthands have at most 6 longhands.
-  DCHECK_LE(shorthand.length(), 6u);
-  const CSSValue* longhands[6] = {nullptr, nullptr, nullptr,
-                                  nullptr, nullptr, nullptr};
-  const CSSProperty** shorthand_properties = shorthand.properties();
-  do {
-    bool found_longhand = false;
-    for (size_t i = 0; !found_longhand && i < shorthand.length(); ++i) {
-      if (longhands[i])
-        continue;
-      longhands[i] = ParseLonghand(shorthand_properties[i]->PropertyID(),
-                                   shorthand.id(), context, range);
-
-      if (longhands[i])
-        found_longhand = true;
-    }
-    if (!found_longhand)
-      return false;
-  } while (!range.AtEnd());
-
-  for (size_t i = 0; i < shorthand.length(); ++i) {
-    if (longhands[i]) {
-      AddProperty(shorthand_properties[i]->PropertyID(), shorthand.id(),
-                  *longhands[i], important, IsImplicitProperty::kNotImplicit,
-                  properties);
-    } else {
-      AddProperty(shorthand_properties[i]->PropertyID(), shorthand.id(),
-                  *CSSInitialValue::Create(), important,
-                  IsImplicitProperty::kNotImplicit, properties);
-    }
-  }
-  return true;
-}
-
-void AddExpandedPropertyForValue(
-    CSSPropertyID property,
-    const CSSValue& value,
-    bool important,
-    HeapVector<CSSPropertyValue, 256>& properties) {
-  const StylePropertyShorthand& shorthand = shorthandForProperty(property);
-  unsigned shorthand_length = shorthand.length();
-  DCHECK(shorthand_length);
-  const CSSProperty** longhands = shorthand.properties();
-  for (unsigned i = 0; i < shorthand_length; ++i) {
-    AddProperty(longhands[i]->PropertyID(), property, value, important,
-                IsImplicitProperty::kNotImplicit, properties);
-  }
-}
-
-}  // namespace css_property_parser_helpers
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h
deleted file mode 100644
index aaa55af..0000000
--- a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h
+++ /dev/null
@@ -1,253 +0,0 @@
-// Copyright 2016 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_CSS_PARSER_CSS_PROPERTY_PARSER_HELPERS_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PARSER_CSS_PROPERTY_PARSER_HELPERS_H_
-
-#include "base/optional.h"
-#include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
-#include "third_party/blink/renderer/core/css/css_function_value.h"
-#include "third_party/blink/renderer/core/css/css_identifier_value.h"
-#include "third_party/blink/renderer/core/css/css_primitive_value.h"
-#include "third_party/blink/renderer/core/css/css_value_list.h"
-#include "third_party/blink/renderer/core/css/parser/css_parser_mode.h"
-#include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
-#include "third_party/blink/renderer/core/frame/web_feature_forward.h"
-#include "third_party/blink/renderer/platform/geometry/length.h"  // For ValueRange
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class CSSParserContext;
-class CSSPropertyValue;
-class CSSStringValue;
-class CSSValuePair;
-class StylePropertyShorthand;
-
-namespace cssvalue {
-
-class CSSURIValue;
-
-}
-
-// When these functions are successful, they will consume all the relevant
-// tokens from the range and also consume any whitespace which follows. When
-// the start of the range doesn't match the type we're looking for, the range
-// will not be modified.
-namespace css_property_parser_helpers {
-
-void Complete4Sides(CSSValue* side[4]);
-
-// TODO(timloh): These should probably just be consumeComma and consumeSlash.
-bool ConsumeCommaIncludingWhitespace(CSSParserTokenRange&);
-bool ConsumeSlashIncludingWhitespace(CSSParserTokenRange&);
-// consumeFunction expects the range starts with a FunctionToken.
-CSSParserTokenRange ConsumeFunction(CSSParserTokenRange&);
-
-enum class UnitlessQuirk { kAllow, kForbid };
-
-CSSPrimitiveValue* ConsumeInteger(
-    CSSParserTokenRange&,
-    const CSSParserContext&,
-    double minimum_value = -std::numeric_limits<double>::max());
-CSSPrimitiveValue* ConsumeIntegerOrNumberCalc(CSSParserTokenRange&,
-                                              const CSSParserContext&);
-CSSPrimitiveValue* ConsumePositiveInteger(CSSParserTokenRange&,
-                                          const CSSParserContext&);
-bool ConsumeNumberRaw(CSSParserTokenRange&,
-                      const CSSParserContext& context,
-                      double& result);
-CSSPrimitiveValue* ConsumeNumber(CSSParserTokenRange&,
-                                 const CSSParserContext&,
-                                 ValueRange);
-CSSPrimitiveValue* ConsumeLength(CSSParserTokenRange&,
-                                 const CSSParserContext&,
-                                 ValueRange,
-                                 UnitlessQuirk = UnitlessQuirk::kForbid);
-CSSPrimitiveValue* ConsumePercent(CSSParserTokenRange&,
-                                  const CSSParserContext&,
-                                  ValueRange);
-CSSPrimitiveValue* ConsumeAlphaValue(CSSParserTokenRange&,
-                                     const CSSParserContext&);
-CSSPrimitiveValue* ConsumeLengthOrPercent(
-    CSSParserTokenRange&,
-    const CSSParserContext&,
-    ValueRange,
-    UnitlessQuirk = UnitlessQuirk::kForbid);
-CSSPrimitiveValue* ConsumeSVGGeometryPropertyLength(CSSParserTokenRange&,
-                                                    const CSSParserContext&,
-                                                    ValueRange);
-
-CSSPrimitiveValue* ConsumeAngle(
-    CSSParserTokenRange&,
-    const CSSParserContext&,
-    base::Optional<WebFeature> unitless_zero_feature);
-CSSPrimitiveValue* ConsumeAngle(
-    CSSParserTokenRange&,
-    const CSSParserContext&,
-    base::Optional<WebFeature> unitless_zero_feature,
-    double minimum_value,
-    double maximum_value);
-CSSPrimitiveValue* ConsumeTime(CSSParserTokenRange&,
-                               const CSSParserContext&,
-                               ValueRange);
-CSSPrimitiveValue* ConsumeResolution(CSSParserTokenRange&);
-
-CSSIdentifierValue* ConsumeIdent(CSSParserTokenRange&);
-CSSIdentifierValue* ConsumeIdentRange(CSSParserTokenRange&,
-                                      CSSValueID lower,
-                                      CSSValueID upper);
-template <CSSValueID, CSSValueID...>
-inline bool IdentMatches(CSSValueID id);
-template <CSSValueID... allowedIdents>
-CSSIdentifierValue* ConsumeIdent(CSSParserTokenRange&);
-
-CSSCustomIdentValue* ConsumeCustomIdent(CSSParserTokenRange&,
-                                        const CSSParserContext&);
-CSSStringValue* ConsumeString(CSSParserTokenRange&);
-StringView ConsumeUrlAsStringView(CSSParserTokenRange&,
-                                  const CSSParserContext&);
-cssvalue::CSSURIValue* ConsumeUrl(CSSParserTokenRange&,
-                                  const CSSParserContext&);
-
-CSSValue* ConsumeColor(CSSParserTokenRange&,
-                       const CSSParserContext&,
-                       bool accept_quirky_colors = false);
-
-CSSValue* ConsumeInternalForcedBackgroundColor(CSSParserTokenRange&,
-                                               const CSSParserContext&);
-
-CSSValue* ConsumeLineWidth(CSSParserTokenRange&,
-                           const CSSParserContext&,
-                           UnitlessQuirk);
-
-CSSValuePair* ConsumePosition(CSSParserTokenRange&,
-                              const CSSParserContext&,
-                              UnitlessQuirk,
-                              base::Optional<WebFeature> three_value_position);
-bool ConsumePosition(CSSParserTokenRange&,
-                     const CSSParserContext&,
-                     UnitlessQuirk,
-                     base::Optional<WebFeature> three_value_position,
-                     CSSValue*& result_x,
-                     CSSValue*& result_y);
-bool ConsumeOneOrTwoValuedPosition(CSSParserTokenRange&,
-                                   const CSSParserContext&,
-                                   UnitlessQuirk,
-                                   CSSValue*& result_x,
-                                   CSSValue*& result_y);
-bool ConsumeBorderShorthand(CSSParserTokenRange&,
-                            const CSSParserContext&,
-                            const CSSValue*& result_width,
-                            const CSSValue*& result_style,
-                            const CSSValue*& result_color);
-
-enum class ConsumeGeneratedImagePolicy { kAllow, kForbid };
-
-CSSValue* ConsumeImage(
-    CSSParserTokenRange&,
-    const CSSParserContext&,
-    ConsumeGeneratedImagePolicy = ConsumeGeneratedImagePolicy::kAllow);
-CSSValue* ConsumeImageOrNone(CSSParserTokenRange&, const CSSParserContext&);
-
-CSSValue* ConsumeAxis(CSSParserTokenRange&, const CSSParserContext& context);
-
-// See also css_parsing_utils::IsCSSWideKeyword.
-CORE_EXPORT bool IsCSSWideKeyword(StringView);
-bool IsRevertKeyword(StringView);
-bool IsDefaultKeyword(StringView);
-
-CSSIdentifierValue* ConsumeShapeBox(CSSParserTokenRange&);
-
-enum class IsImplicitProperty { kNotImplicit, kImplicit };
-
-void AddProperty(CSSPropertyID resolved_property,
-                 CSSPropertyID current_shorthand,
-                 const CSSValue&,
-                 bool important,
-                 IsImplicitProperty,
-                 HeapVector<CSSPropertyValue, 256>& properties);
-
-void CountKeywordOnlyPropertyUsage(CSSPropertyID,
-                                   const CSSParserContext&,
-                                   CSSValueID);
-
-const CSSValue* ParseLonghand(CSSPropertyID unresolved_property,
-                              CSSPropertyID current_shorthand,
-                              const CSSParserContext&,
-                              CSSParserTokenRange&);
-
-bool ConsumeShorthandVia2Longhands(
-    const StylePropertyShorthand&,
-    bool important,
-    const CSSParserContext&,
-    CSSParserTokenRange&,
-    HeapVector<CSSPropertyValue, 256>& properties);
-
-bool ConsumeShorthandVia4Longhands(
-    const StylePropertyShorthand&,
-    bool important,
-    const CSSParserContext&,
-    CSSParserTokenRange&,
-    HeapVector<CSSPropertyValue, 256>& properties);
-
-bool ConsumeShorthandGreedilyViaLonghands(
-    const StylePropertyShorthand&,
-    bool important,
-    const CSSParserContext&,
-    CSSParserTokenRange&,
-    HeapVector<CSSPropertyValue, 256>& properties);
-
-void AddExpandedPropertyForValue(CSSPropertyID prop_id,
-                                 const CSSValue&,
-                                 bool,
-                                 HeapVector<CSSPropertyValue, 256>& properties);
-
-// Template implementations are at the bottom of the file for readability.
-
-template <typename... emptyBaseCase>
-inline bool IdentMatches(CSSValueID id) {
-  return false;
-}
-template <CSSValueID head, CSSValueID... tail>
-inline bool IdentMatches(CSSValueID id) {
-  return id == head || IdentMatches<tail...>(id);
-}
-
-template <CSSValueID... names>
-CSSIdentifierValue* ConsumeIdent(CSSParserTokenRange& range) {
-  if (range.Peek().GetType() != kIdentToken ||
-      !IdentMatches<names...>(range.Peek().Id()))
-    return nullptr;
-  return CSSIdentifierValue::Create(range.ConsumeIncludingWhitespace().Id());
-}
-
-// ConsumeCommaSeparatedList takes a callback function to call on each item in
-// the list, followed by the arguments to pass to this callback.
-// The first argument to the callback must be the CSSParserTokenRange
-template <typename Func, typename... Args>
-CSSValueList* ConsumeCommaSeparatedList(Func callback,
-                                        CSSParserTokenRange& range,
-                                        Args&&... args) {
-  CSSValueList* list = CSSValueList::CreateCommaSeparated();
-  do {
-    CSSValue* value = callback(range, std::forward<Args>(args)...);
-    if (!value)
-      return nullptr;
-    list->Append(*value);
-  } while (ConsumeCommaIncludingWhitespace(range));
-  DCHECK(list->length());
-  return list;
-}
-
-CSSValue* ConsumeTransformValue(CSSParserTokenRange&, const CSSParserContext&);
-CSSValue* ConsumeTransformList(CSSParserTokenRange&, const CSSParserContext&);
-CSSValue* ConsumeFilterFunctionList(CSSParserTokenRange&,
-                                    const CSSParserContext&);
-
-}  // namespace css_property_parser_helpers
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PARSER_CSS_PROPERTY_PARSER_HELPERS_H_
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers_test.cc b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers_test.cc
deleted file mode 100644
index 2eb068a..0000000
--- a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers_test.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-TEST(CSSPropertyParserHelpersTest, ParseRevert) {
-  {
-    ScopedCSSRevertForTest scoped_revert(true);
-    EXPECT_TRUE(css_property_parser_helpers::IsCSSWideKeyword("revert"));
-  }
-
-  {
-    ScopedCSSRevertForTest scoped_revert(false);
-    EXPECT_FALSE(css_property_parser_helpers::IsCSSWideKeyword("revert"));
-  }
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/parser/font_variant_east_asian_parser.h b/third_party/blink/renderer/core/css/parser/font_variant_east_asian_parser.h
index d8f4be15..ad052d3e 100644
--- a/third_party/blink/renderer/core/css/parser/font_variant_east_asian_parser.h
+++ b/third_party/blink/renderer/core/css/parser/font_variant_east_asian_parser.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/core/css/css_value_list.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
-#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
 
 namespace blink {
 
@@ -33,20 +33,18 @@
       case CSSValueID::kTraditional:
         if (east_asian_form_value_)
           return ParseResult::kDisallowedValue;
-        east_asian_form_value_ =
-            css_property_parser_helpers::ConsumeIdent(range);
+        east_asian_form_value_ = css_parsing_utils::ConsumeIdent(range);
         return ParseResult::kConsumedValue;
       case CSSValueID::kFullWidth:
       case CSSValueID::kProportionalWidth:
         if (east_asian_width_value_)
           return ParseResult::kDisallowedValue;
-        east_asian_width_value_ =
-            css_property_parser_helpers::ConsumeIdent(range);
+        east_asian_width_value_ = css_parsing_utils::ConsumeIdent(range);
         return ParseResult::kConsumedValue;
       case CSSValueID::kRuby:
         if (ruby_value_)
           return ParseResult::kDisallowedValue;
-        ruby_value_ = css_property_parser_helpers::ConsumeIdent(range);
+        ruby_value_ = css_parsing_utils::ConsumeIdent(range);
         return ParseResult::kConsumedValue;
       default:
         return ParseResult::kUnknownValue;
diff --git a/third_party/blink/renderer/core/css/parser/font_variant_ligatures_parser.h b/third_party/blink/renderer/core/css/parser/font_variant_ligatures_parser.h
index 9da8977..255833f9 100644
--- a/third_party/blink/renderer/core/css/parser/font_variant_ligatures_parser.h
+++ b/third_party/blink/renderer/core/css/parser/font_variant_ligatures_parser.h
@@ -8,7 +8,7 @@
 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
 #include "third_party/blink/renderer/core/css/css_value_list.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
-#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
 
 namespace blink {
 
@@ -55,7 +55,7 @@
       default:
         return ParseResult::kUnknownValue;
     }
-    result_->Append(*css_property_parser_helpers::ConsumeIdent(range));
+    result_->Append(*css_parsing_utils::ConsumeIdent(range));
     return ParseResult::kConsumedValue;
   }
 
diff --git a/third_party/blink/renderer/core/css/parser/font_variant_numeric_parser.h b/third_party/blink/renderer/core/css/parser/font_variant_numeric_parser.h
index f34b7ae..c6df51a 100644
--- a/third_party/blink/renderer/core/css/parser/font_variant_numeric_parser.h
+++ b/third_party/blink/renderer/core/css/parser/font_variant_numeric_parser.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/core/css/css_value_list.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
-#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
 
 namespace blink {
 
@@ -26,29 +26,29 @@
       case CSSValueID::kOldstyleNums:
         if (numeric_figure_)
           return ParseResult::kDisallowedValue;
-        numeric_figure_ = css_property_parser_helpers::ConsumeIdent(range);
+        numeric_figure_ = css_parsing_utils::ConsumeIdent(range);
         return ParseResult::kConsumedValue;
       case CSSValueID::kProportionalNums:
       case CSSValueID::kTabularNums:
         if (numeric_spacing_)
           return ParseResult::kDisallowedValue;
-        numeric_spacing_ = css_property_parser_helpers::ConsumeIdent(range);
+        numeric_spacing_ = css_parsing_utils::ConsumeIdent(range);
         return ParseResult::kConsumedValue;
       case CSSValueID::kDiagonalFractions:
       case CSSValueID::kStackedFractions:
         if (numeric_fraction_)
           return ParseResult::kDisallowedValue;
-        numeric_fraction_ = css_property_parser_helpers::ConsumeIdent(range);
+        numeric_fraction_ = css_parsing_utils::ConsumeIdent(range);
         return ParseResult::kConsumedValue;
       case CSSValueID::kOrdinal:
         if (ordinal_)
           return ParseResult::kDisallowedValue;
-        ordinal_ = css_property_parser_helpers::ConsumeIdent(range);
+        ordinal_ = css_parsing_utils::ConsumeIdent(range);
         return ParseResult::kConsumedValue;
       case CSSValueID::kSlashedZero:
         if (slashed_zero_)
           return ParseResult::kDisallowedValue;
-        slashed_zero_ = css_property_parser_helpers::ConsumeIdent(range);
+        slashed_zero_ = css_parsing_utils::ConsumeIdent(range);
         return ParseResult::kConsumedValue;
       default:
         return ParseResult::kUnknownValue;
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
index 4c57e3cc..d81bcaa 100644
--- a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
@@ -2705,11 +2705,12 @@
   return list;
 }
 
-CSSValue* ComputedStyleUtils::ValueForGapLength(const GapLength& gap_length,
-                                                const ComputedStyle& style) {
-  if (gap_length.IsNormal())
+CSSValue* ComputedStyleUtils::ValueForGapLength(
+    const base::Optional<Length>& gap_length,
+    const ComputedStyle& style) {
+  if (!gap_length)
     return CSSIdentifierValue::Create(CSSValueID::kNormal);
-  return ZoomAdjustedPixelValueForLength(gap_length.GetLength(), style);
+  return ZoomAdjustedPixelValueForLength(*gap_length, style);
 }
 
 CSSValue* ComputedStyleUtils::ValueForStyleName(const StyleName& name) {
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.h b/third_party/blink/renderer/core/css/properties/computed_style_utils.h
index 3acd1dd..decc9f2a 100644
--- a/third_party/blink/renderer/core/css/properties/computed_style_utils.h
+++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.h
@@ -238,10 +238,10 @@
                                                 bool allow_visited_style);
   static CSSValue* ScrollCustomizationFlagsToCSSValue(
       scroll_customization::ScrollDirection);
-  static CSSValue* ValueForGapLength(const GapLength&, const ComputedStyle&);
+  static CSSValue* ValueForGapLength(const base::Optional<Length>&,
+                                     const ComputedStyle&);
   static CSSValue* ValueForStyleName(const StyleName&);
   static CSSValue* ValueForStyleNameOrKeyword(const StyleNameOrKeyword&);
-
   static std::unique_ptr<CrossThreadStyleValue>
   CrossThreadStyleValueFromCSSStyleValue(CSSStyleValue* style_value);
 
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
index 5f5a0f1..cbcb9d1 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -7,25 +7,35 @@
 #include <memory>
 #include <utility>
 
+#include "third_party/blink/renderer/core/css/css_axis_value.h"
 #include "third_party/blink/renderer/core/css/css_basic_shape_values.h"
 #include "third_party/blink/renderer/core/css/css_border_image.h"
+#include "third_party/blink/renderer/core/css/css_color_value.h"
 #include "third_party/blink/renderer/core/css/css_content_distribution_value.h"
+#include "third_party/blink/renderer/core/css/css_crossfade_value.h"
 #include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
 #include "third_party/blink/renderer/core/css/css_font_family_value.h"
 #include "third_party/blink/renderer/core/css/css_font_feature_value.h"
 #include "third_party/blink/renderer/core/css/css_font_style_range_value.h"
 #include "third_party/blink/renderer/core/css/css_function_value.h"
+#include "third_party/blink/renderer/core/css/css_gradient_value.h"
 #include "third_party/blink/renderer/core/css/css_grid_auto_repeat_value.h"
 #include "third_party/blink/renderer/core/css/css_grid_integer_repeat_value.h"
 #include "third_party/blink/renderer/core/css/css_grid_line_names_value.h"
 #include "third_party/blink/renderer/core/css/css_grid_template_areas_value.h"
 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
+#include "third_party/blink/renderer/core/css/css_image_set_value.h"
+#include "third_party/blink/renderer/core/css/css_image_value.h"
 #include "third_party/blink/renderer/core/css/css_initial_value.h"
+#include "third_party/blink/renderer/core/css/css_light_dark_value_pair.h"
+#include "third_party/blink/renderer/core/css/css_math_expression_node.h"
 #include "third_party/blink/renderer/core/css/css_math_function_value.h"
 #include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
+#include "third_party/blink/renderer/core/css/css_paint_value.h"
 #include "third_party/blink/renderer/core/css/css_path_value.h"
 #include "third_party/blink/renderer/core/css/css_primitive_value.h"
 #include "third_party/blink/renderer/core/css/css_property_names.h"
+#include "third_party/blink/renderer/core/css/css_property_value.h"
 #include "third_party/blink/renderer/core/css/css_ray_value.h"
 #include "third_party/blink/renderer/core/css/css_shadow_value.h"
 #include "third_party/blink/renderer/core/css/css_string_value.h"
@@ -34,17 +44,21 @@
 #include "third_party/blink/renderer/core/css/css_value.h"
 #include "third_party/blink/renderer/core/css/css_value_list.h"
 #include "third_party/blink/renderer/core/css/css_value_pair.h"
+#include "third_party/blink/renderer/core/css/css_variable_data.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
+#include "third_party/blink/renderer/core/css/parser/css_parser_fast_paths.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_idioms.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_local_context.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_token.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
-#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
 #include "third_party/blink/renderer/core/css/properties/css_property.h"
 #include "third_party/blink/renderer/core/css/properties/longhand.h"
+#include "third_party/blink/renderer/core/css/style_color.h"
 #include "third_party/blink/renderer/core/css_value_keywords.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/style_property_shorthand.h"
 #include "third_party/blink/renderer/core/svg/svg_parsing_error.h"
 #include "third_party/blink/renderer/core/svg/svg_path_utilities.h"
@@ -65,34 +79,28 @@
 namespace {
 
 bool IsLeftOrRightKeyword(CSSValueID id) {
-  return css_property_parser_helpers::IdentMatches<CSSValueID::kLeft,
-                                                   CSSValueID::kRight>(id);
+  return IdentMatches<CSSValueID::kLeft, CSSValueID::kRight>(id);
 }
 
 bool IsAuto(CSSValueID id) {
-  return css_property_parser_helpers::IdentMatches<CSSValueID::kAuto>(id);
+  return IdentMatches<CSSValueID::kAuto>(id);
 }
 
 bool IsNormalOrStretch(CSSValueID id) {
-  return css_property_parser_helpers::IdentMatches<CSSValueID::kNormal,
-                                                   CSSValueID::kStretch>(id);
+  return IdentMatches<CSSValueID::kNormal, CSSValueID::kStretch>(id);
 }
 
 bool IsContentDistributionKeyword(CSSValueID id) {
-  return css_property_parser_helpers::IdentMatches<
-      CSSValueID::kSpaceBetween, CSSValueID::kSpaceAround,
-      CSSValueID::kSpaceEvenly, CSSValueID::kStretch>(id);
+  return IdentMatches<CSSValueID::kSpaceBetween, CSSValueID::kSpaceAround,
+                      CSSValueID::kSpaceEvenly, CSSValueID::kStretch>(id);
 }
 
 bool IsOverflowKeyword(CSSValueID id) {
-  return css_property_parser_helpers::IdentMatches<CSSValueID::kUnsafe,
-                                                   CSSValueID::kSafe>(id);
+  return IdentMatches<CSSValueID::kUnsafe, CSSValueID::kSafe>(id);
 }
 
 CSSIdentifierValue* ConsumeOverflowPositionKeyword(CSSParserTokenRange& range) {
-  return IsOverflowKeyword(range.Peek().Id())
-             ? css_property_parser_helpers::ConsumeIdent(range)
-             : nullptr;
+  return IsOverflowKeyword(range.Peek().Id()) ? ConsumeIdent(range) : nullptr;
 }
 
 CSSValueID GetBaselineKeyword(CSSValue& value) {
@@ -111,10 +119,8 @@
 
 CSSValue* ConsumeBaselineKeyword(CSSParserTokenRange& range) {
   CSSIdentifierValue* preference =
-      css_property_parser_helpers::ConsumeIdent<CSSValueID::kFirst,
-                                                CSSValueID::kLast>(range);
-  CSSIdentifierValue* baseline =
-      css_property_parser_helpers::ConsumeIdent<CSSValueID::kBaseline>(range);
+      ConsumeIdent<CSSValueID::kFirst, CSSValueID::kLast>(range);
+  CSSIdentifierValue* baseline = ConsumeIdent<CSSValueID::kBaseline>(range);
   if (!baseline)
     return nullptr;
   if (preference && preference->GetValueID() == CSSValueID::kLast) {
@@ -128,17 +134,15 @@
                        const CSSParserContext& context) {
   DCHECK_EQ(range.Peek().FunctionId(), CSSValueID::kSteps);
   CSSParserTokenRange range_copy = range;
-  CSSParserTokenRange args =
-      css_property_parser_helpers::ConsumeFunction(range_copy);
+  CSSParserTokenRange args = ConsumeFunction(range_copy);
 
-  CSSPrimitiveValue* steps =
-      css_property_parser_helpers::ConsumePositiveInteger(args, context);
+  CSSPrimitiveValue* steps = ConsumePositiveInteger(args, context);
   if (!steps)
     return nullptr;
 
   StepsTimingFunction::StepPosition position =
       StepsTimingFunction::StepPosition::END;
-  if (css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args)) {
+  if (ConsumeCommaIncludingWhitespace(args)) {
     switch (args.ConsumeIncludingWhitespace().Id()) {
       case CSSValueID::kStart:
         position = StepsTimingFunction::StepPosition::START;
@@ -187,20 +191,16 @@
                              const CSSParserContext& context) {
   DCHECK_EQ(range.Peek().FunctionId(), CSSValueID::kCubicBezier);
   CSSParserTokenRange range_copy = range;
-  CSSParserTokenRange args =
-      css_property_parser_helpers::ConsumeFunction(range_copy);
+  CSSParserTokenRange args = ConsumeFunction(range_copy);
 
   double x1, y1, x2, y2;
-  if (css_property_parser_helpers::ConsumeNumberRaw(args, context, x1) &&
-      x1 >= 0 && x1 <= 1 &&
-      css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args) &&
-      css_property_parser_helpers::ConsumeNumberRaw(args, context, y1) &&
-      css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args) &&
-      css_property_parser_helpers::ConsumeNumberRaw(args, context, x2) &&
-      x2 >= 0 && x2 <= 1 &&
-      css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args) &&
-      css_property_parser_helpers::ConsumeNumberRaw(args, context, y2) &&
-      args.AtEnd()) {
+  if (ConsumeNumberRaw(args, context, x1) && x1 >= 0 && x1 <= 1 &&
+      ConsumeCommaIncludingWhitespace(args) &&
+      ConsumeNumberRaw(args, context, y1) &&
+      ConsumeCommaIncludingWhitespace(args) &&
+      ConsumeNumberRaw(args, context, x2) && x2 >= 0 && x2 <= 1 &&
+      ConsumeCommaIncludingWhitespace(args) &&
+      ConsumeNumberRaw(args, context, y2) && args.AtEnd()) {
     range = range_copy;
     return MakeGarbageCollected<cssvalue::CSSCubicBezierTimingFunctionValue>(
         x1, y1, x2, y2);
@@ -211,14 +211,12 @@
 
 CSSIdentifierValue* ConsumeBorderImageRepeatKeyword(
     CSSParserTokenRange& range) {
-  return css_property_parser_helpers::ConsumeIdent<
-      CSSValueID::kStretch, CSSValueID::kRepeat, CSSValueID::kSpace,
-      CSSValueID::kRound>(range);
+  return ConsumeIdent<CSSValueID::kStretch, CSSValueID::kRepeat,
+                      CSSValueID::kSpace, CSSValueID::kRound>(range);
 }
 
 bool ConsumeCSSValueId(CSSParserTokenRange& range, CSSValueID& value) {
-  CSSIdentifierValue* keyword =
-      css_property_parser_helpers::ConsumeIdent(range);
+  CSSIdentifierValue* keyword = ConsumeIdent(range);
   if (!keyword || !range.AtEnd())
     return false;
   value = keyword->GetValueID();
@@ -227,12 +225,10 @@
 
 CSSValue* ConsumeShapeRadius(CSSParserTokenRange& args,
                              const CSSParserContext& context) {
-  if (css_property_parser_helpers::IdentMatches<CSSValueID::kClosestSide,
-                                                CSSValueID::kFarthestSide>(
+  if (IdentMatches<CSSValueID::kClosestSide, CSSValueID::kFarthestSide>(
           args.Peek().Id()))
-    return css_property_parser_helpers::ConsumeIdent(args);
-  return css_property_parser_helpers::ConsumeLengthOrPercent(
-      args, context, kValueRangeNonNegative);
+    return ConsumeIdent(args);
+  return ConsumeLengthOrPercent(args, context, kValueRangeNonNegative);
 }
 
 cssvalue::CSSBasicShapeCircleValue* ConsumeBasicShapeCircle(
@@ -243,11 +239,10 @@
   auto* shape = MakeGarbageCollected<cssvalue::CSSBasicShapeCircleValue>();
   if (CSSValue* radius = ConsumeShapeRadius(args, context))
     shape->SetRadius(radius);
-  if (css_property_parser_helpers::ConsumeIdent<CSSValueID::kAt>(args)) {
+  if (ConsumeIdent<CSSValueID::kAt>(args)) {
     CSSValue* center_x = nullptr;
     CSSValue* center_y = nullptr;
-    if (!ConsumePosition(args, context,
-                         css_property_parser_helpers::UnitlessQuirk::kForbid,
+    if (!ConsumePosition(args, context, UnitlessQuirk::kForbid,
                          base::Optional<WebFeature>(), center_x, center_y))
       return nullptr;
     shape->SetCenterX(center_x);
@@ -265,18 +260,16 @@
   WebFeature feature = WebFeature::kBasicShapeEllipseNoRadius;
   if (CSSValue* radius_x = ConsumeShapeRadius(args, context)) {
     CSSValue* radius_y = ConsumeShapeRadius(args, context);
-    if (!radius_y) {
+    if (!radius_y)
       return nullptr;
-    }
     shape->SetRadiusX(radius_x);
     shape->SetRadiusY(radius_y);
     feature = WebFeature::kBasicShapeEllipseTwoRadius;
   }
-  if (css_property_parser_helpers::ConsumeIdent<CSSValueID::kAt>(args)) {
+  if (ConsumeIdent<CSSValueID::kAt>(args)) {
     CSSValue* center_x = nullptr;
     CSSValue* center_y = nullptr;
-    if (!ConsumePosition(args, context,
-                         css_property_parser_helpers::UnitlessQuirk::kForbid,
+    if (!ConsumePosition(args, context, UnitlessQuirk::kForbid,
                          base::Optional<WebFeature>(), center_x, center_y))
       return nullptr;
     shape->SetCenterX(center_x);
@@ -290,30 +283,27 @@
     CSSParserTokenRange& args,
     const CSSParserContext& context) {
   auto* shape = MakeGarbageCollected<cssvalue::CSSBasicShapePolygonValue>();
-  if (css_property_parser_helpers::IdentMatches<CSSValueID::kEvenodd,
-                                                CSSValueID::kNonzero>(
+  if (IdentMatches<CSSValueID::kEvenodd, CSSValueID::kNonzero>(
           args.Peek().Id())) {
     shape->SetWindRule(args.ConsumeIncludingWhitespace().Id() ==
                                CSSValueID::kEvenodd
                            ? RULE_EVENODD
                            : RULE_NONZERO);
-    if (!css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args))
+    if (!ConsumeCommaIncludingWhitespace(args))
       return nullptr;
   }
 
   do {
     CSSPrimitiveValue* x_length =
-        css_property_parser_helpers::ConsumeLengthOrPercent(args, context,
-                                                            kValueRangeAll);
+        ConsumeLengthOrPercent(args, context, kValueRangeAll);
     if (!x_length)
       return nullptr;
     CSSPrimitiveValue* y_length =
-        css_property_parser_helpers::ConsumeLengthOrPercent(args, context,
-                                                            kValueRangeAll);
+        ConsumeLengthOrPercent(args, context, kValueRangeAll);
     if (!y_length)
       return nullptr;
     shape->AppendPoint(x_length, y_length);
-  } while (css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args));
+  } while (ConsumeCommaIncludingWhitespace(args));
   return shape;
 }
 
@@ -321,22 +311,18 @@
     CSSParserTokenRange& args,
     const CSSParserContext& context) {
   auto* shape = MakeGarbageCollected<cssvalue::CSSBasicShapeInsetValue>();
-  CSSPrimitiveValue* top = css_property_parser_helpers::ConsumeLengthOrPercent(
-      args, context, kValueRangeAll);
+  CSSPrimitiveValue* top =
+      ConsumeLengthOrPercent(args, context, kValueRangeAll);
   if (!top)
     return nullptr;
   CSSPrimitiveValue* right =
-      css_property_parser_helpers::ConsumeLengthOrPercent(args, context,
-                                                          kValueRangeAll);
+      ConsumeLengthOrPercent(args, context, kValueRangeAll);
   CSSPrimitiveValue* bottom = nullptr;
   CSSPrimitiveValue* left = nullptr;
   if (right) {
-    bottom = css_property_parser_helpers::ConsumeLengthOrPercent(
-        args, context, kValueRangeAll);
-    if (bottom) {
-      left = css_property_parser_helpers::ConsumeLengthOrPercent(
-          args, context, kValueRangeAll);
-    }
+    bottom = ConsumeLengthOrPercent(args, context, kValueRangeAll);
+    if (bottom)
+      left = ConsumeLengthOrPercent(args, context, kValueRangeAll);
   }
   if (left)
     shape->UpdateShapeSize4Values(top, right, bottom, left);
@@ -347,7 +333,7 @@
   else
     shape->UpdateShapeSize1Value(top);
 
-  if (css_property_parser_helpers::ConsumeIdent<CSSValueID::kRound>(args)) {
+  if (ConsumeIdent<CSSValueID::kRound>(args)) {
     CSSValue* horizontal_radii[4] = {nullptr};
     CSSValue* vertical_radii[4] = {nullptr};
     if (!ConsumeRadii(horizontal_radii, vertical_radii, args, context, false))
@@ -373,15 +359,12 @@
                     CSSFunctionValue*& transform_value,
                     unsigned number_of_arguments) {
   do {
-    CSSValue* parsed_value = css_property_parser_helpers::ConsumeNumber(
-        args, context, kValueRangeAll);
+    CSSValue* parsed_value = ConsumeNumber(args, context, kValueRangeAll);
     if (!parsed_value)
       return false;
     transform_value->Append(*parsed_value);
-    if (--number_of_arguments &&
-        !css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args)) {
+    if (--number_of_arguments && !ConsumeCommaIncludingWhitespace(args))
       return false;
-    }
   } while (number_of_arguments);
   return true;
 }
@@ -390,15 +373,12 @@
                         const CSSParserContext& context,
                         CSSFunctionValue*& transform_value,
                         bool use_legacy_parsing) {
-  CSSPrimitiveValue* parsed_value = css_property_parser_helpers::ConsumeLength(
-      args, context, kValueRangeNonNegative);
+  CSSPrimitiveValue* parsed_value =
+      ConsumeLength(args, context, kValueRangeNonNegative);
   if (!parsed_value && use_legacy_parsing) {
     double perspective;
-    if (!css_property_parser_helpers::ConsumeNumberRaw(args, context,
-                                                       perspective) ||
-        perspective < 0) {
+    if (!ConsumeNumberRaw(args, context, perspective) || perspective < 0)
       return false;
-    }
     context.Count(WebFeature::kUnitlessPerspectiveInTransformProperty);
     parsed_value = CSSNumericLiteralValue::Create(
         perspective, CSSPrimitiveValue::UnitType::kPixels);
@@ -415,34 +395,2167 @@
   unsigned number_of_arguments = 2;
   CSSValue* parsed_value = nullptr;
   do {
-    parsed_value = css_property_parser_helpers::ConsumeLengthOrPercent(
-        args, context, kValueRangeAll);
+    parsed_value = ConsumeLengthOrPercent(args, context, kValueRangeAll);
     if (!parsed_value)
       return false;
     transform_value->Append(*parsed_value);
-    if (!css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args))
+    if (!ConsumeCommaIncludingWhitespace(args))
       return false;
   } while (--number_of_arguments);
-  parsed_value =
-      css_property_parser_helpers::ConsumeLength(args, context, kValueRangeAll);
+  parsed_value = ConsumeLength(args, context, kValueRangeAll);
   if (!parsed_value)
     return false;
   transform_value->Append(*parsed_value);
   return true;
 }
 
+// Add CSSVariableData to variableData vector.
+bool AddCSSPaintArgument(
+    const Vector<CSSParserToken>& tokens,
+    Vector<scoped_refptr<CSSVariableData>>* const variable_data,
+    const CSSParserContext& context) {
+  CSSParserTokenRange token_range(tokens);
+  if (!token_range.AtEnd()) {
+    scoped_refptr<CSSVariableData> unparsed_css_variable_data =
+        CSSVariableData::Create(token_range, false, false, context.BaseURL(),
+                                context.Charset());
+    if (unparsed_css_variable_data.get()) {
+      variable_data->push_back(std::move(unparsed_css_variable_data));
+      return true;
+    }
+  }
+  return false;
+}
+
+// Consume input arguments, if encounter function, will return the function
+// block as a Vector of CSSParserToken, otherwise, will just return a Vector of
+// a single CSSParserToken.
+Vector<CSSParserToken> ConsumeFunctionArgsOrNot(CSSParserTokenRange& args) {
+  Vector<CSSParserToken> argument_tokens;
+  if (args.Peek().GetBlockType() == CSSParserToken::kBlockStart) {
+    // Function block.
+    // Push the function name and initial right parenthesis.
+    // Since we don't have any upfront knowledge about the input argument types
+    // here, we should just leave the token as it is and resolve it later in
+    // the variable parsing phase.
+    argument_tokens.push_back(args.Peek());
+    CSSParserTokenRange contents = args.ConsumeBlock();
+    while (!contents.AtEnd())
+      argument_tokens.push_back(contents.Consume());
+    argument_tokens.push_back(
+        CSSParserToken(kRightParenthesisToken, CSSParserToken::kBlockEnd));
+
+  } else {
+    argument_tokens.push_back(args.ConsumeIncludingWhitespace());
+  }
+  return argument_tokens;
+}
+
+CSSFunctionValue* ConsumeFilterFunction(CSSParserTokenRange& range,
+                                        const CSSParserContext& context) {
+  CSSValueID filter_type = range.Peek().FunctionId();
+  if (filter_type < CSSValueID::kInvert ||
+      filter_type > CSSValueID::kDropShadow)
+    return nullptr;
+  CSSParserTokenRange args = ConsumeFunction(range);
+  CSSFunctionValue* filter_value =
+      MakeGarbageCollected<CSSFunctionValue>(filter_type);
+  CSSValue* parsed_value = nullptr;
+
+  if (filter_type == CSSValueID::kDropShadow) {
+    parsed_value =
+        ParseSingleShadow(args, context, AllowInsetAndSpread::kForbid);
+  } else {
+    if (args.AtEnd()) {
+      context.Count(WebFeature::kCSSFilterFunctionNoArguments);
+      return filter_value;
+    }
+    if (filter_type == CSSValueID::kBrightness) {
+      // FIXME (crbug.com/397061): Support calc expressions like calc(10% + 0.5)
+      parsed_value = ConsumePercent(args, context, kValueRangeAll);
+      if (!parsed_value)
+        parsed_value = ConsumeNumber(args, context, kValueRangeNonNegative);
+    } else if (filter_type == CSSValueID::kHueRotate) {
+      parsed_value =
+          ConsumeAngle(args, context, WebFeature::kUnitlessZeroAngleFilter);
+    } else if (filter_type == CSSValueID::kBlur) {
+      CSSParserContext::ParserModeOverridingScope scope(context,
+                                                        kHTMLStandardMode);
+      parsed_value = ConsumeLength(args, context, kValueRangeNonNegative);
+    } else {
+      // FIXME (crbug.com/397061): Support calc expressions like calc(10% + 0.5)
+      parsed_value = ConsumePercent(args, context, kValueRangeNonNegative);
+      if (!parsed_value)
+        parsed_value = ConsumeNumber(args, context, kValueRangeNonNegative);
+      if (parsed_value && filter_type != CSSValueID::kSaturate &&
+          filter_type != CSSValueID::kContrast) {
+        bool is_percentage =
+            To<CSSPrimitiveValue>(parsed_value)->IsPercentage();
+        double max_allowed = is_percentage ? 100.0 : 1.0;
+        if (To<CSSPrimitiveValue>(parsed_value)->GetDoubleValue() >
+            max_allowed) {
+          parsed_value = CSSNumericLiteralValue::Create(
+              max_allowed, is_percentage
+                               ? CSSPrimitiveValue::UnitType::kPercentage
+                               : CSSPrimitiveValue::UnitType::kNumber);
+        }
+      }
+    }
+  }
+  if (!parsed_value || !args.AtEnd())
+    return nullptr;
+  filter_value->Append(*parsed_value);
+  return filter_value;
+}
+
+template <typename Func, typename... Args>
+CSSLightDarkValuePair* ConsumeInternalLightDark(Func consume_value,
+                                                CSSParserTokenRange& range,
+                                                const CSSParserContext& context,
+                                                Args&&... args) {
+  if (range.Peek().FunctionId() != CSSValueID::kInternalLightDark)
+    return nullptr;
+  if (!isValueAllowedInMode(CSSValueID::kInternalLightDark, context.Mode()))
+    return nullptr;
+  CSSParserTokenRange range_copy = range;
+  CSSParserTokenRange arg_range = ConsumeFunction(range_copy);
+  CSSValue* light_value =
+      consume_value(arg_range, context, std::forward<Args>(args)...);
+  if (!light_value || !ConsumeCommaIncludingWhitespace(arg_range))
+    return nullptr;
+  CSSValue* dark_value =
+      consume_value(arg_range, context, std::forward<Args>(args)...);
+  if (!dark_value || !arg_range.AtEnd())
+    return nullptr;
+  range = range_copy;
+  return MakeGarbageCollected<CSSLightDarkValuePair>(light_value, dark_value);
+}
+
 }  // namespace
 
+void Complete4Sides(CSSValue* side[4]) {
+  if (side[3])
+    return;
+  if (!side[2]) {
+    if (!side[1])
+      side[1] = side[0];
+    side[2] = side[0];
+  }
+  side[3] = side[1];
+}
+
+bool ConsumeCommaIncludingWhitespace(CSSParserTokenRange& range) {
+  CSSParserToken value = range.Peek();
+  if (value.GetType() != kCommaToken)
+    return false;
+  range.ConsumeIncludingWhitespace();
+  return true;
+}
+
+bool ConsumeSlashIncludingWhitespace(CSSParserTokenRange& range) {
+  CSSParserToken value = range.Peek();
+  if (value.GetType() != kDelimiterToken || value.Delimiter() != '/')
+    return false;
+  range.ConsumeIncludingWhitespace();
+  return true;
+}
+
+CSSParserTokenRange ConsumeFunction(CSSParserTokenRange& range) {
+  DCHECK_EQ(range.Peek().GetType(), kFunctionToken);
+  CSSParserTokenRange contents = range.ConsumeBlock();
+  range.ConsumeWhitespace();
+  contents.ConsumeWhitespace();
+  return contents;
+}
+
+// TODO(rwlbuis): consider pulling in the parsing logic from
+// css_math_expression_node.cc.
+class MathFunctionParser {
+  STACK_ALLOCATED();
+
+ public:
+  MathFunctionParser(CSSParserTokenRange& range,
+                     const CSSParserContext& context,
+                     ValueRange value_range)
+      : source_range_(range), range_(range) {
+    const CSSParserToken& token = range.Peek();
+    switch (token.FunctionId()) {
+      case CSSValueID::kCalc:
+      case CSSValueID::kWebkitCalc:
+        calc_value_ = CSSMathFunctionValue::Create(
+            CSSMathExpressionNode::ParseCalc(ConsumeFunction(range_)),
+            value_range);
+        break;
+      case CSSValueID::kMin:
+        calc_value_ = CSSMathFunctionValue::Create(
+            CSSMathExpressionNode::ParseMin(ConsumeFunction(range_)),
+            value_range);
+        break;
+      case CSSValueID::kMax:
+        calc_value_ = CSSMathFunctionValue::Create(
+            CSSMathExpressionNode::ParseMax(ConsumeFunction(range_)),
+            value_range);
+        break;
+      case CSSValueID::kClamp:
+        calc_value_ = CSSMathFunctionValue::Create(
+            CSSMathExpressionNode::ParseClamp(ConsumeFunction(range_)),
+            value_range);
+        break;
+      default:
+        break;
+    }
+    if (calc_value_ && calc_value_->HasComparisons())
+      context.Count(WebFeature::kCSSComparisonFunctions);
+  }
+
+  explicit MathFunctionParser(CSSParserTokenRange& range,
+                              const CSSParserContext& context)
+      : MathFunctionParser(range, context, kValueRangeAll) {}
+
+  const CSSMathFunctionValue* Value() const { return calc_value_; }
+  CSSMathFunctionValue* ConsumeValue() {
+    if (!calc_value_)
+      return nullptr;
+    source_range_ = range_;
+    CSSMathFunctionValue* result = calc_value_;
+    calc_value_ = nullptr;
+    return result;
+  }
+
+  CSSPrimitiveValue* ConsumeRoundedInt() {
+    if (!calc_value_)
+      return nullptr;
+    source_range_ = range_;
+    CSSPrimitiveValue::UnitType unit_type =
+        CSSPrimitiveValue::UnitType::kInteger;
+    double rounded_value = floor(calc_value_->GetDoubleValue() + 0.5);
+    return CSSNumericLiteralValue::Create(rounded_value, unit_type);
+  }
+
+  CSSPrimitiveValue* ConsumeNumber() {
+    if (!calc_value_)
+      return nullptr;
+    source_range_ = range_;
+    CSSPrimitiveValue::UnitType unit_type =
+        calc_value_->IsInt() ? CSSPrimitiveValue::UnitType::kInteger
+                             : CSSPrimitiveValue::UnitType::kNumber;
+    return CSSNumericLiteralValue::Create(calc_value_->GetDoubleValue(),
+                                          unit_type);
+  }
+
+  bool ConsumeNumberRaw(double& result) {
+    if (!calc_value_ || calc_value_->Category() != kCalcNumber)
+      return false;
+    source_range_ = range_;
+    result = calc_value_->GetDoubleValue();
+    return true;
+  }
+
+ private:
+  CSSParserTokenRange& source_range_;
+  CSSParserTokenRange range_;
+  CSSMathFunctionValue* calc_value_ = nullptr;
+};
+
+CSSPrimitiveValue* ConsumeInteger(CSSParserTokenRange& range,
+                                  const CSSParserContext& context,
+                                  double minimum_value) {
+  const CSSParserToken& token = range.Peek();
+  if (token.GetType() == kNumberToken) {
+    if (token.GetNumericValueType() == kNumberValueType ||
+        token.NumericValue() < minimum_value)
+      return nullptr;
+    return CSSNumericLiteralValue::Create(
+        range.ConsumeIncludingWhitespace().NumericValue(),
+        CSSPrimitiveValue::UnitType::kInteger);
+  }
+  MathFunctionParser math_parser(range, context);
+  if (const CSSMathFunctionValue* math_value = math_parser.Value()) {
+    if (!RuntimeEnabledFeatures::CSSCalcAsIntEnabled() && !math_value->IsInt())
+      return nullptr;
+    if (math_value->Category() != kCalcNumber)
+      return nullptr;
+    double double_value = math_value->GetDoubleValue();
+    if (double_value < minimum_value)
+      return nullptr;
+    if (!RuntimeEnabledFeatures::CSSCalcAsIntEnabled())
+      return math_parser.ConsumeNumber();
+    if (math_value->IsInt())
+      return math_parser.ConsumeNumber();
+    return math_parser.ConsumeRoundedInt();
+  }
+  return nullptr;
+}
+
+// This implements the behavior defined in [1], where calc() expressions
+// are valid when <integer> is expected, even if the calc()-expression does
+// not result in an integral value.
+//
+// TODO(andruud): Eventually this behavior should just be part of
+// ConsumeInteger, and this function can be removed. For now, having a separate
+// function with this behavior allows us to implement [1] gradually.
+//
+// [1] https://drafts.csswg.org/css-values-4/#calc-type-checking
+CSSPrimitiveValue* ConsumeIntegerOrNumberCalc(CSSParserTokenRange& range,
+                                              const CSSParserContext& context) {
+  CSSParserTokenRange int_range(range);
+  if (CSSPrimitiveValue* value = ConsumeInteger(int_range, context)) {
+    range = int_range;
+    return value;
+  }
+  MathFunctionParser math_parser(range, context);
+  if (const CSSMathFunctionValue* calculation = math_parser.Value()) {
+    if (calculation->Category() != kCalcNumber)
+      return nullptr;
+    return math_parser.ConsumeValue();
+  }
+  return nullptr;
+}
+
+CSSPrimitiveValue* ConsumePositiveInteger(CSSParserTokenRange& range,
+                                          const CSSParserContext& context) {
+  return ConsumeInteger(range, context, 1);
+}
+
+bool ConsumeNumberRaw(CSSParserTokenRange& range,
+                      const CSSParserContext& context,
+                      double& result) {
+  if (range.Peek().GetType() == kNumberToken) {
+    result = range.ConsumeIncludingWhitespace().NumericValue();
+    return true;
+  }
+  MathFunctionParser math_parser(range, context, kValueRangeAll);
+  return math_parser.ConsumeNumberRaw(result);
+}
+
+// TODO(timloh): Work out if this can just call consumeNumberRaw
+CSSPrimitiveValue* ConsumeNumber(CSSParserTokenRange& range,
+                                 const CSSParserContext& context,
+                                 ValueRange value_range) {
+  const CSSParserToken& token = range.Peek();
+  if (token.GetType() == kNumberToken) {
+    if (value_range == kValueRangeNonNegative && token.NumericValue() < 0)
+      return nullptr;
+    return CSSNumericLiteralValue::Create(
+        range.ConsumeIncludingWhitespace().NumericValue(), token.GetUnitType());
+  }
+  MathFunctionParser math_parser(range, context, kValueRangeAll);
+  if (const CSSMathFunctionValue* calculation = math_parser.Value()) {
+    // TODO(rwlbuis) Calcs should not be subject to parse time range checks.
+    // spec: https://drafts.csswg.org/css-values-3/#calc-range
+    if (calculation->Category() != kCalcNumber ||
+        (value_range == kValueRangeNonNegative && calculation->IsNegative()))
+      return nullptr;
+    return math_parser.ConsumeNumber();
+  }
+  return nullptr;
+}
+
+inline bool ShouldAcceptUnitlessLength(double value,
+                                       CSSParserMode css_parser_mode,
+                                       UnitlessQuirk unitless) {
+  return value == 0 || css_parser_mode == kSVGAttributeMode ||
+         (css_parser_mode == kHTMLQuirksMode &&
+          unitless == UnitlessQuirk::kAllow);
+}
+
+CSSPrimitiveValue* ConsumeLength(CSSParserTokenRange& range,
+                                 const CSSParserContext& context,
+                                 ValueRange value_range,
+                                 UnitlessQuirk unitless) {
+  const CSSParserToken& token = range.Peek();
+  if (token.GetType() == kDimensionToken) {
+    switch (token.GetUnitType()) {
+      case CSSPrimitiveValue::UnitType::kQuirkyEms:
+        if (context.Mode() != kUASheetMode)
+          return nullptr;
+        FALLTHROUGH;
+      case CSSPrimitiveValue::UnitType::kEms:
+      case CSSPrimitiveValue::UnitType::kRems:
+      case CSSPrimitiveValue::UnitType::kChs:
+      case CSSPrimitiveValue::UnitType::kExs:
+      case CSSPrimitiveValue::UnitType::kPixels:
+      case CSSPrimitiveValue::UnitType::kCentimeters:
+      case CSSPrimitiveValue::UnitType::kMillimeters:
+      case CSSPrimitiveValue::UnitType::kQuarterMillimeters:
+      case CSSPrimitiveValue::UnitType::kInches:
+      case CSSPrimitiveValue::UnitType::kPoints:
+      case CSSPrimitiveValue::UnitType::kPicas:
+      case CSSPrimitiveValue::UnitType::kUserUnits:
+      case CSSPrimitiveValue::UnitType::kViewportWidth:
+      case CSSPrimitiveValue::UnitType::kViewportHeight:
+      case CSSPrimitiveValue::UnitType::kViewportMin:
+      case CSSPrimitiveValue::UnitType::kViewportMax:
+        break;
+      default:
+        return nullptr;
+    }
+    if (value_range == kValueRangeNonNegative && token.NumericValue() < 0)
+      return nullptr;
+    return CSSNumericLiteralValue::Create(
+        range.ConsumeIncludingWhitespace().NumericValue(), token.GetUnitType());
+  }
+  if (token.GetType() == kNumberToken) {
+    if (!ShouldAcceptUnitlessLength(token.NumericValue(), context.Mode(),
+                                    unitless) ||
+        (value_range == kValueRangeNonNegative && token.NumericValue() < 0))
+      return nullptr;
+    CSSPrimitiveValue::UnitType unit_type =
+        CSSPrimitiveValue::UnitType::kPixels;
+    if (context.Mode() == kSVGAttributeMode)
+      unit_type = CSSPrimitiveValue::UnitType::kUserUnits;
+    return CSSNumericLiteralValue::Create(
+        range.ConsumeIncludingWhitespace().NumericValue(), unit_type);
+  }
+  if (context.Mode() == kSVGAttributeMode)
+    return nullptr;
+  MathFunctionParser math_parser(range, context, value_range);
+  if (math_parser.Value() && math_parser.Value()->Category() == kCalcLength)
+    return math_parser.ConsumeValue();
+  return nullptr;
+}
+
+CSSPrimitiveValue* ConsumePercent(CSSParserTokenRange& range,
+                                  const CSSParserContext& context,
+                                  ValueRange value_range) {
+  const CSSParserToken& token = range.Peek();
+  if (token.GetType() == kPercentageToken) {
+    if (value_range == kValueRangeNonNegative && token.NumericValue() < 0)
+      return nullptr;
+    return CSSNumericLiteralValue::Create(
+        range.ConsumeIncludingWhitespace().NumericValue(),
+        CSSPrimitiveValue::UnitType::kPercentage);
+  }
+  MathFunctionParser math_parser(range, context, value_range);
+  if (const CSSMathFunctionValue* calculation = math_parser.Value()) {
+    if (calculation->Category() == kCalcPercent)
+      return math_parser.ConsumeValue();
+  }
+  return nullptr;
+}
+
+CSSPrimitiveValue* ConsumeAlphaValue(CSSParserTokenRange& range,
+                                     const CSSParserContext& context) {
+  if (CSSPrimitiveValue* value =
+          ConsumeNumber(range, context, kValueRangeAll)) {
+    return value;
+  }
+  if (CSSPrimitiveValue* value =
+          ConsumePercent(range, context, kValueRangeAll)) {
+    return CSSNumericLiteralValue::Create(value->GetDoubleValue() / 100.0,
+                                          CSSPrimitiveValue::UnitType::kNumber);
+  }
+  return nullptr;
+}
+
+bool CanConsumeCalcValue(CalculationCategory category,
+                         CSSParserMode css_parser_mode) {
+  return category == kCalcLength || category == kCalcPercent ||
+         category == kCalcPercentLength ||
+         (css_parser_mode == kSVGAttributeMode && category == kCalcNumber);
+}
+
+CSSPrimitiveValue* ConsumeLengthOrPercent(CSSParserTokenRange& range,
+                                          const CSSParserContext& context,
+                                          ValueRange value_range,
+                                          UnitlessQuirk unitless) {
+  const CSSParserToken& token = range.Peek();
+  if (token.GetType() == kDimensionToken || token.GetType() == kNumberToken)
+    return ConsumeLength(range, context, value_range, unitless);
+  if (token.GetType() == kPercentageToken)
+    return ConsumePercent(range, context, value_range);
+  MathFunctionParser math_parser(range, context, value_range);
+  if (const CSSMathFunctionValue* calculation = math_parser.Value()) {
+    if (CanConsumeCalcValue(calculation->Category(), context.Mode()))
+      return math_parser.ConsumeValue();
+  }
+  return nullptr;
+}
+
+namespace {
+
+bool IsNonZeroUserUnitsValue(const CSSPrimitiveValue* value) {
+  if (!value)
+    return false;
+  if (const auto* numeric_literal = DynamicTo<CSSNumericLiteralValue>(value)) {
+    return numeric_literal->GetType() ==
+               CSSPrimitiveValue::UnitType::kUserUnits &&
+           value->GetDoubleValue() != 0;
+  }
+  const auto& math_value = To<CSSMathFunctionValue>(*value);
+  return math_value.Category() == kCalcNumber && math_value.DoubleValue() != 0;
+}
+
+}  // namespace
+
+CSSPrimitiveValue* ConsumeSVGGeometryPropertyLength(
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    ValueRange value_range) {
+  CSSParserContext::ParserModeOverridingScope scope(context, kSVGAttributeMode);
+  CSSPrimitiveValue* value = ConsumeLengthOrPercent(range, context, value_range,
+                                                    UnitlessQuirk::kForbid);
+  if (IsNonZeroUserUnitsValue(value))
+    context.Count(WebFeature::kSVGGeometryPropertyHasNonZeroUnitlessValue);
+  return value;
+}
+
+CSSPrimitiveValue* ConsumeGradientLengthOrPercent(
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    ValueRange value_range,
+    UnitlessQuirk unitless) {
+  return ConsumeLengthOrPercent(range, context, value_range, unitless);
+}
+
+CSSPrimitiveValue* ConsumeAngle(
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    base::Optional<WebFeature> unitless_zero_feature,
+    double minimum_value,
+    double maximum_value) {
+  const CSSParserToken& token = range.Peek();
+  if (token.GetType() == kDimensionToken) {
+    switch (token.GetUnitType()) {
+      case CSSPrimitiveValue::UnitType::kDegrees:
+      case CSSPrimitiveValue::UnitType::kRadians:
+      case CSSPrimitiveValue::UnitType::kGradians:
+      case CSSPrimitiveValue::UnitType::kTurns:
+        return CSSNumericLiteralValue::Create(
+            range.ConsumeIncludingWhitespace().NumericValue(),
+            token.GetUnitType());
+      default:
+        return nullptr;
+    }
+  }
+  if (token.GetType() == kNumberToken && token.NumericValue() == 0 &&
+      unitless_zero_feature) {
+    range.ConsumeIncludingWhitespace();
+    context.Count(*unitless_zero_feature);
+    return CSSNumericLiteralValue::Create(
+        0, CSSPrimitiveValue::UnitType::kDegrees);
+  }
+  MathFunctionParser math_parser(range, context, kValueRangeAll);
+  if (const CSSMathFunctionValue* calculation = math_parser.Value()) {
+    if (calculation->Category() != kCalcAngle)
+      return nullptr;
+    if (CSSMathFunctionValue* result = math_parser.ConsumeValue()) {
+      if (result->ComputeDegrees() < minimum_value) {
+        return CSSNumericLiteralValue::Create(
+            minimum_value, CSSPrimitiveValue::UnitType::kDegrees);
+      }
+      if (result->ComputeDegrees() > maximum_value) {
+        return CSSNumericLiteralValue::Create(
+            maximum_value, CSSPrimitiveValue::UnitType::kDegrees);
+      }
+      return result;
+    }
+  }
+  return nullptr;
+}
+
+CSSPrimitiveValue* ConsumeAngle(
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    base::Optional<WebFeature> unitless_zero_feature) {
+  return ConsumeAngle(range, context, std::move(unitless_zero_feature),
+                      std::numeric_limits<double>::lowest(),
+                      std::numeric_limits<double>::max());
+}
+
+CSSPrimitiveValue* ConsumeTime(CSSParserTokenRange& range,
+                               const CSSParserContext& context,
+                               ValueRange value_range) {
+  const CSSParserToken& token = range.Peek();
+  if (token.GetType() == kDimensionToken) {
+    if (value_range == kValueRangeNonNegative && token.NumericValue() < 0)
+      return nullptr;
+    CSSPrimitiveValue::UnitType unit = token.GetUnitType();
+    if (unit == CSSPrimitiveValue::UnitType::kMilliseconds ||
+        unit == CSSPrimitiveValue::UnitType::kSeconds) {
+      return CSSNumericLiteralValue::Create(
+          range.ConsumeIncludingWhitespace().NumericValue(),
+          token.GetUnitType());
+    }
+    return nullptr;
+  }
+  MathFunctionParser math_parser(range, context, value_range);
+  if (const CSSMathFunctionValue* calculation = math_parser.Value()) {
+    if (calculation->Category() == kCalcTime)
+      return math_parser.ConsumeValue();
+  }
+  return nullptr;
+}
+
+CSSPrimitiveValue* ConsumeResolution(CSSParserTokenRange& range) {
+  const CSSParserToken& token = range.Peek();
+  // Unlike the other types, calc() does not work with <resolution>.
+  if (token.GetType() != kDimensionToken)
+    return nullptr;
+  CSSPrimitiveValue::UnitType unit = token.GetUnitType();
+  if (unit == CSSPrimitiveValue::UnitType::kDotsPerPixel ||
+      unit == CSSPrimitiveValue::UnitType::kDotsPerInch ||
+      unit == CSSPrimitiveValue::UnitType::kDotsPerCentimeter) {
+    return CSSNumericLiteralValue::Create(
+        range.ConsumeIncludingWhitespace().NumericValue(), unit);
+  }
+  return nullptr;
+}
+
+CSSIdentifierValue* ConsumeIdent(CSSParserTokenRange& range) {
+  if (range.Peek().GetType() != kIdentToken)
+    return nullptr;
+  return CSSIdentifierValue::Create(range.ConsumeIncludingWhitespace().Id());
+}
+
+CSSIdentifierValue* ConsumeIdentRange(CSSParserTokenRange& range,
+                                      CSSValueID lower,
+                                      CSSValueID upper) {
+  if (range.Peek().Id() < lower || range.Peek().Id() > upper)
+    return nullptr;
+  return ConsumeIdent(range);
+}
+
+CSSCustomIdentValue* ConsumeCustomIdentWithToken(
+    const CSSParserToken& token,
+    const CSSParserContext& context) {
+  if (token.GetType() != kIdentToken || IsCSSWideKeyword(token.Value()))
+    return nullptr;
+
+  if (EqualIgnoringASCIICase(token.Value(), "default"))
+    context.Count(WebFeature::kDefaultInCustomIdent);
+
+  return MakeGarbageCollected<CSSCustomIdentValue>(
+      token.Value().ToAtomicString());
+}
+
+CSSCustomIdentValue* ConsumeCustomIdent(CSSParserTokenRange& range,
+                                        const CSSParserContext& context) {
+  if (range.Peek().GetType() != kIdentToken ||
+      IsCSSWideKeyword(range.Peek().Value()))
+    return nullptr;
+
+  return ConsumeCustomIdentWithToken(range.ConsumeIncludingWhitespace(),
+                                     context);
+}
+
+CSSStringValue* ConsumeString(CSSParserTokenRange& range) {
+  if (range.Peek().GetType() != kStringToken)
+    return nullptr;
+  return MakeGarbageCollected<CSSStringValue>(
+      range.ConsumeIncludingWhitespace().Value().ToString());
+}
+
+StringView ConsumeUrlAsStringView(CSSParserTokenRange& range,
+                                  const CSSParserContext& context) {
+  StringView url;
+  const CSSParserToken& token = range.Peek();
+  if (token.GetType() == kUrlToken) {
+    range.ConsumeIncludingWhitespace();
+    url = token.Value();
+  } else if (token.FunctionId() == CSSValueID::kUrl) {
+    CSSParserTokenRange url_range = range;
+    CSSParserTokenRange url_args = url_range.ConsumeBlock();
+    const CSSParserToken& next = url_args.ConsumeIncludingWhitespace();
+    if (next.GetType() == kBadStringToken || !url_args.AtEnd())
+      return StringView();
+    DCHECK_EQ(next.GetType(), kStringToken);
+    range = url_range;
+    range.ConsumeWhitespace();
+    url = next.Value();
+  }
+
+  // Invalidate the URL if only data URLs are allowed and the protocol is not
+  // data.
+  if (!url.IsNull() &&
+      context.ResourceFetchRestriction() ==
+          ResourceFetchRestriction::kOnlyDataUrls &&
+      !ProtocolIs(url.ToString(), "data")) {
+    // The StringView must be instantiated with an empty string otherwise the
+    // URL will incorrectly be identified as null. The resource should behave as
+    // if it failed to load.
+    url = StringView("");
+  }
+
+  return url;
+}
+
+cssvalue::CSSURIValue* ConsumeUrl(CSSParserTokenRange& range,
+                                  const CSSParserContext& context) {
+  StringView url = ConsumeUrlAsStringView(range, context);
+  if (url.IsNull())
+    return nullptr;
+  AtomicString url_string(url.ToString());
+  return MakeGarbageCollected<cssvalue::CSSURIValue>(
+      url_string, context.CompleteURL(url_string));
+}
+
+static int ClampRGBComponent(const CSSPrimitiveValue& value) {
+  double result = value.GetDoubleValue();
+  if (value.IsPercentage()) {
+    // 2.55 cannot be precisely represented as a double
+    result = (result / 100.0) * 255.0;
+  }
+  return clampTo<int>(round(result), 0, 255);
+}
+
+static bool ParseRGBParameters(CSSParserTokenRange& range,
+                               const CSSParserContext& context,
+                               RGBA32& result) {
+  DCHECK(range.Peek().FunctionId() == CSSValueID::kRgb ||
+         range.Peek().FunctionId() == CSSValueID::kRgba);
+  CSSParserTokenRange args = ConsumeFunction(range);
+  CSSPrimitiveValue* color_parameter =
+      ConsumeNumber(args, context, kValueRangeAll);
+  if (!color_parameter)
+    color_parameter = ConsumePercent(args, context, kValueRangeAll);
+  if (!color_parameter)
+    return false;
+  const bool is_percent = color_parameter->IsPercentage();
+  int color_array[3];
+  color_array[0] = ClampRGBComponent(*color_parameter);
+  bool requires_commas = false;
+  for (int i = 1; i < 3; i++) {
+    if (ConsumeCommaIncludingWhitespace(args)) {
+      if (i != 1 && !requires_commas)
+        return false;
+      requires_commas = true;
+    } else if (requires_commas || args.AtEnd()) {
+      return false;
+    }
+    color_parameter = is_percent ? ConsumePercent(args, context, kValueRangeAll)
+                                 : ConsumeNumber(args, context, kValueRangeAll);
+    if (!color_parameter)
+      return false;
+    color_array[i] = ClampRGBComponent(*color_parameter);
+  }
+
+  bool comma_consumed = ConsumeCommaIncludingWhitespace(args);
+  bool slash_consumed = ConsumeSlashIncludingWhitespace(args);
+  if ((comma_consumed && !requires_commas) ||
+      (slash_consumed && requires_commas))
+    return false;
+  if (comma_consumed || slash_consumed) {
+    double alpha;
+    if (!ConsumeNumberRaw(args, context, alpha)) {
+      CSSPrimitiveValue* alpha_percent =
+          ConsumePercent(args, context, kValueRangeAll);
+      if (!alpha_percent)
+        return false;
+      else
+        alpha = alpha_percent->GetDoubleValue() / 100.0;
+    }
+    // W3 standard stipulates a 2.55 alpha value multiplication factor.
+    int alpha_component =
+        static_cast<int>(lround(clampTo<double>(alpha, 0.0, 1.0) * 255.0));
+    result = MakeRGBA(color_array[0], color_array[1], color_array[2],
+                      alpha_component);
+  } else {
+    result = MakeRGB(color_array[0], color_array[1], color_array[2]);
+  }
+  return args.AtEnd();
+}
+
+static bool ParseHSLParameters(CSSParserTokenRange& range,
+                               const CSSParserContext& context,
+                               RGBA32& result) {
+  DCHECK(range.Peek().FunctionId() == CSSValueID::kHsl ||
+         range.Peek().FunctionId() == CSSValueID::kHsla);
+  CSSParserTokenRange args = ConsumeFunction(range);
+  CSSPrimitiveValue* hsl_value = ConsumeAngle(args, context, base::nullopt);
+  double angle_value;
+  if (!hsl_value) {
+    hsl_value = ConsumeNumber(args, context, kValueRangeAll);
+    if (!hsl_value)
+      return false;
+    angle_value = hsl_value->GetDoubleValue();
+  } else {
+    angle_value = hsl_value->ComputeDegrees();
+  }
+  double color_array[3];
+  color_array[0] = fmod(fmod(angle_value, 360.0) + 360.0, 360.0) / 60.0;
+  bool requires_commas = false;
+  for (int i = 1; i < 3; i++) {
+    if (ConsumeCommaIncludingWhitespace(args)) {
+      if (i != 1 && !requires_commas)
+        return false;
+      requires_commas = true;
+    } else if (requires_commas || args.AtEnd()) {
+      return false;
+    }
+    hsl_value = ConsumePercent(args, context, kValueRangeAll);
+    if (!hsl_value)
+      return false;
+    double double_value = hsl_value->GetDoubleValue();
+    color_array[i] = clampTo<double>(double_value, 0.0, 100.0) /
+                     100.0;  // Needs to be value between 0 and 1.0.
+  }
+
+  double alpha = 1.0;
+  bool comma_consumed = ConsumeCommaIncludingWhitespace(args);
+  bool slash_consumed = ConsumeSlashIncludingWhitespace(args);
+  if ((comma_consumed && !requires_commas) ||
+      (slash_consumed && requires_commas))
+    return false;
+  if (comma_consumed || slash_consumed) {
+    if (!ConsumeNumberRaw(args, context, alpha)) {
+      CSSPrimitiveValue* alpha_percent =
+          ConsumePercent(args, context, kValueRangeAll);
+      if (!alpha_percent)
+        return false;
+      else
+        alpha = alpha_percent->GetDoubleValue() / 100.0;
+    }
+    alpha = clampTo<double>(alpha, 0.0, 1.0);
+  }
+  result =
+      MakeRGBAFromHSLA(color_array[0], color_array[1], color_array[2], alpha);
+  return args.AtEnd();
+}
+
+static bool ParseHexColor(CSSParserTokenRange& range,
+                          RGBA32& result,
+                          bool accept_quirky_colors) {
+  const CSSParserToken& token = range.Peek();
+  if (token.GetType() == kHashToken) {
+    if (!Color::ParseHexColor(token.Value(), result))
+      return false;
+  } else if (accept_quirky_colors) {
+    String color;
+    if (token.GetType() == kNumberToken || token.GetType() == kDimensionToken) {
+      if (token.GetNumericValueType() != kIntegerValueType ||
+          token.NumericValue() < 0. || token.NumericValue() >= 1000000.)
+        return false;
+      if (token.GetType() == kNumberToken) {  // e.g. 112233
+        color = String::Format("%d", static_cast<int>(token.NumericValue()));
+      } else {  // e.g. 0001FF
+        color = String::Number(static_cast<int>(token.NumericValue())) +
+                token.Value().ToString();
+      }
+      while (color.length() < 6)
+        color = "0" + color;
+    } else if (token.GetType() == kIdentToken) {  // e.g. FF0000
+      color = token.Value().ToString();
+    }
+    unsigned length = color.length();
+    if (length != 3 && length != 6)
+      return false;
+    if (!Color::ParseHexColor(color, result))
+      return false;
+  } else {
+    return false;
+  }
+  range.ConsumeIncludingWhitespace();
+  return true;
+}
+
+static bool ParseColorFunction(CSSParserTokenRange& range,
+                               const CSSParserContext& context,
+                               RGBA32& result) {
+  CSSValueID function_id = range.Peek().FunctionId();
+  if (function_id < CSSValueID::kRgb || function_id > CSSValueID::kHsla)
+    return false;
+  CSSParserTokenRange color_range = range;
+  if ((function_id <= CSSValueID::kRgba &&
+       !ParseRGBParameters(color_range, context, result)) ||
+      (function_id >= CSSValueID::kHsl &&
+       !ParseHSLParameters(color_range, context, result)))
+    return false;
+  range = color_range;
+  return true;
+}
+
+CSSValue* ConsumeColor(CSSParserTokenRange& range,
+                       const CSSParserContext& context,
+                       bool accept_quirky_colors) {
+  CSSValueID id = range.Peek().Id();
+  if (StyleColor::IsColorKeyword(id)) {
+    if (!isValueAllowedInMode(id, context.Mode()))
+      return nullptr;
+    CSSIdentifierValue* color = ConsumeIdent(range);
+    return color;
+  }
+  RGBA32 color = Color::kTransparent;
+  if (!ParseHexColor(range, color, accept_quirky_colors) &&
+      !ParseColorFunction(range, context, color)) {
+    return ConsumeInternalLightDark(ConsumeColor, range, context,
+                                    accept_quirky_colors);
+  }
+  return cssvalue::CSSColorValue::Create(color);
+}
+
+CSSValue* ConsumeInternalForcedBackgroundColor(
+    CSSParserTokenRange& range,
+    const CSSParserContext& context) {
+  CSSValueID id = range.Peek().Id();
+  if (!StyleColor::IsColorKeyword(id))
+    return nullptr;
+  return ConsumeIdent(range);
+}
+
+CSSValue* ConsumeLineWidth(CSSParserTokenRange& range,
+                           const CSSParserContext& context,
+                           UnitlessQuirk unitless) {
+  CSSValueID id = range.Peek().Id();
+  if (id == CSSValueID::kThin || id == CSSValueID::kMedium ||
+      id == CSSValueID::kThick)
+    return ConsumeIdent(range);
+  return ConsumeLength(range, context, kValueRangeNonNegative, unitless);
+}
+
+static CSSValue* ConsumePositionComponent(CSSParserTokenRange& range,
+                                          const CSSParserContext& context,
+                                          UnitlessQuirk unitless,
+                                          bool& horizontal_edge,
+                                          bool& vertical_edge) {
+  if (range.Peek().GetType() != kIdentToken)
+    return ConsumeLengthOrPercent(range, context, kValueRangeAll, unitless);
+
+  CSSValueID id = range.Peek().Id();
+  if (id == CSSValueID::kLeft || id == CSSValueID::kRight) {
+    if (horizontal_edge)
+      return nullptr;
+    horizontal_edge = true;
+  } else if (id == CSSValueID::kTop || id == CSSValueID::kBottom) {
+    if (vertical_edge)
+      return nullptr;
+    vertical_edge = true;
+  } else if (id != CSSValueID::kCenter) {
+    return nullptr;
+  }
+  return ConsumeIdent(range);
+}
+
+static bool IsHorizontalPositionKeywordOnly(const CSSValue& value) {
+  auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
+  if (!identifier_value)
+    return false;
+  CSSValueID value_id = identifier_value->GetValueID();
+  return value_id == CSSValueID::kLeft || value_id == CSSValueID::kRight;
+}
+
+static bool IsVerticalPositionKeywordOnly(const CSSValue& value) {
+  auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
+  if (!identifier_value)
+    return false;
+  CSSValueID value_id = identifier_value->GetValueID();
+  return value_id == CSSValueID::kTop || value_id == CSSValueID::kBottom;
+}
+
+static void PositionFromOneValue(CSSValue* value,
+                                 CSSValue*& result_x,
+                                 CSSValue*& result_y) {
+  bool value_applies_to_y_axis_only = IsVerticalPositionKeywordOnly(*value);
+  result_x = value;
+  result_y = CSSIdentifierValue::Create(CSSValueID::kCenter);
+  if (value_applies_to_y_axis_only)
+    std::swap(result_x, result_y);
+}
+
+static void PositionFromTwoValues(CSSValue* value1,
+                                  CSSValue* value2,
+                                  CSSValue*& result_x,
+                                  CSSValue*& result_y) {
+  bool must_order_as_xy = IsHorizontalPositionKeywordOnly(*value1) ||
+                          IsVerticalPositionKeywordOnly(*value2) ||
+                          !value1->IsIdentifierValue() ||
+                          !value2->IsIdentifierValue();
+  bool must_order_as_yx = IsVerticalPositionKeywordOnly(*value1) ||
+                          IsHorizontalPositionKeywordOnly(*value2);
+  DCHECK(!must_order_as_xy || !must_order_as_yx);
+  result_x = value1;
+  result_y = value2;
+  if (must_order_as_yx)
+    std::swap(result_x, result_y);
+}
+
+static void PositionFromThreeOrFourValues(CSSValue** values,
+                                          CSSValue*& result_x,
+                                          CSSValue*& result_y) {
+  CSSIdentifierValue* center = nullptr;
+  for (int i = 0; values[i]; i++) {
+    auto* current_value = To<CSSIdentifierValue>(values[i]);
+    CSSValueID id = current_value->GetValueID();
+
+    if (id == CSSValueID::kCenter) {
+      DCHECK(!center);
+      center = current_value;
+      continue;
+    }
+
+    CSSValue* result = nullptr;
+    if (values[i + 1] && !values[i + 1]->IsIdentifierValue()) {
+      result = MakeGarbageCollected<CSSValuePair>(
+          current_value, values[++i], CSSValuePair::kKeepIdenticalValues);
+    } else {
+      result = current_value;
+    }
+
+    if (id == CSSValueID::kLeft || id == CSSValueID::kRight) {
+      DCHECK(!result_x);
+      result_x = result;
+    } else {
+      DCHECK(id == CSSValueID::kTop || id == CSSValueID::kBottom);
+      DCHECK(!result_y);
+      result_y = result;
+    }
+  }
+
+  if (center) {
+    DCHECK(!!result_x != !!result_y);
+    if (!result_x)
+      result_x = center;
+    else
+      result_y = center;
+  }
+
+  DCHECK(result_x && result_y);
+}
+
+bool ConsumePosition(CSSParserTokenRange& range,
+                     const CSSParserContext& context,
+                     UnitlessQuirk unitless,
+                     base::Optional<WebFeature> three_value_position,
+                     CSSValue*& result_x,
+                     CSSValue*& result_y) {
+  bool horizontal_edge = false;
+  bool vertical_edge = false;
+  CSSValue* value1 = ConsumePositionComponent(range, context, unitless,
+                                              horizontal_edge, vertical_edge);
+  if (!value1)
+    return false;
+  if (!value1->IsIdentifierValue())
+    horizontal_edge = true;
+
+  CSSParserTokenRange range_after_first_consume = range;
+  CSSValue* value2 = ConsumePositionComponent(range, context, unitless,
+                                              horizontal_edge, vertical_edge);
+  if (!value2) {
+    PositionFromOneValue(value1, result_x, result_y);
+    return true;
+  }
+
+  CSSParserTokenRange range_after_second_consume = range;
+  CSSValue* value3 = nullptr;
+  auto* identifier_value1 = DynamicTo<CSSIdentifierValue>(value1);
+  auto* identifier_value2 = DynamicTo<CSSIdentifierValue>(value2);
+  // TODO(crbug.com/940442): Fix the strange comparison of a
+  // CSSIdentifierValue instance against a specific "range peek" type check.
+  if (identifier_value1 &&
+      !!identifier_value2 != (range.Peek().GetType() == kIdentToken) &&
+      (identifier_value2
+           ? identifier_value2->GetValueID()
+           : identifier_value1->GetValueID()) != CSSValueID::kCenter) {
+    value3 = ConsumePositionComponent(range, context, unitless, horizontal_edge,
+                                      vertical_edge);
+  }
+  if (!value3) {
+    if (vertical_edge && !value2->IsIdentifierValue()) {
+      range = range_after_first_consume;
+      PositionFromOneValue(value1, result_x, result_y);
+      return true;
+    }
+    PositionFromTwoValues(value1, value2, result_x, result_y);
+    return true;
+  }
+
+  CSSValue* value4 = nullptr;
+  auto* identifier_value3 = DynamicTo<CSSIdentifierValue>(value3);
+  if (identifier_value3 &&
+      identifier_value3->GetValueID() != CSSValueID::kCenter &&
+      range.Peek().GetType() != kIdentToken) {
+    value4 = ConsumePositionComponent(range, context, unitless, horizontal_edge,
+                                      vertical_edge);
+  }
+
+  if (!value4) {
+    if (!three_value_position) {
+      // [top | bottom] <length-percentage> is not permitted
+      if (vertical_edge && !value2->IsIdentifierValue()) {
+        range = range_after_first_consume;
+        PositionFromOneValue(value1, result_x, result_y);
+        return true;
+      }
+      range = range_after_second_consume;
+      PositionFromTwoValues(value1, value2, result_x, result_y);
+      return true;
+    }
+    DCHECK_EQ(*three_value_position,
+              WebFeature::kThreeValuedPositionBackground);
+    context.Count(*three_value_position);
+  }
+
+  CSSValue* values[5];
+  values[0] = value1;
+  values[1] = value2;
+  values[2] = value3;
+  values[3] = value4;
+  values[4] = nullptr;
+  PositionFromThreeOrFourValues(values, result_x, result_y);
+  return true;
+}
+
+CSSValuePair* ConsumePosition(CSSParserTokenRange& range,
+                              const CSSParserContext& context,
+                              UnitlessQuirk unitless,
+                              base::Optional<WebFeature> three_value_position) {
+  CSSValue* result_x = nullptr;
+  CSSValue* result_y = nullptr;
+  if (ConsumePosition(range, context, unitless, three_value_position, result_x,
+                      result_y)) {
+    return MakeGarbageCollected<CSSValuePair>(
+        result_x, result_y, CSSValuePair::kKeepIdenticalValues);
+  }
+  return nullptr;
+}
+
+bool ConsumeOneOrTwoValuedPosition(CSSParserTokenRange& range,
+                                   const CSSParserContext& context,
+                                   UnitlessQuirk unitless,
+                                   CSSValue*& result_x,
+                                   CSSValue*& result_y) {
+  bool horizontal_edge = false;
+  bool vertical_edge = false;
+  CSSValue* value1 = ConsumePositionComponent(range, context, unitless,
+                                              horizontal_edge, vertical_edge);
+  if (!value1)
+    return false;
+  if (!value1->IsIdentifierValue())
+    horizontal_edge = true;
+
+  if (vertical_edge &&
+      ConsumeLengthOrPercent(range, context, kValueRangeAll, unitless)) {
+    // <length-percentage> is not permitted after top | bottom.
+    return false;
+  }
+  CSSValue* value2 = ConsumePositionComponent(range, context, unitless,
+                                              horizontal_edge, vertical_edge);
+  if (!value2) {
+    PositionFromOneValue(value1, result_x, result_y);
+    return true;
+  }
+  PositionFromTwoValues(value1, value2, result_x, result_y);
+  return true;
+}
+
+bool ConsumeBorderShorthand(CSSParserTokenRange& range,
+                            const CSSParserContext& context,
+                            const CSSValue*& result_width,
+                            const CSSValue*& result_style,
+                            const CSSValue*& result_color) {
+  while (!result_width || !result_style || !result_color) {
+    if (!result_width) {
+      result_width = ConsumeLineWidth(range, context, UnitlessQuirk::kForbid);
+      if (result_width)
+        continue;
+    }
+    if (!result_style) {
+      result_style = ParseLonghand(CSSPropertyID::kBorderLeftStyle,
+                                   CSSPropertyID::kBorder, context, range);
+      if (result_style)
+        continue;
+    }
+    if (!result_color) {
+      result_color = ConsumeColor(range, context);
+      if (result_color)
+        continue;
+    }
+    break;
+  }
+
+  if (!result_width && !result_style && !result_color)
+    return false;
+
+  if (!result_width)
+    result_width = CSSInitialValue::Create();
+  if (!result_style)
+    result_style = CSSInitialValue::Create();
+  if (!result_color)
+    result_color = CSSInitialValue::Create();
+  return true;
+}
+
+// This should go away once we drop support for -webkit-gradient
+static CSSPrimitiveValue* ConsumeDeprecatedGradientPoint(
+    CSSParserTokenRange& args,
+    const CSSParserContext& context,
+    bool horizontal) {
+  if (args.Peek().GetType() == kIdentToken) {
+    if ((horizontal && ConsumeIdent<CSSValueID::kLeft>(args)) ||
+        (!horizontal && ConsumeIdent<CSSValueID::kTop>(args))) {
+      return CSSNumericLiteralValue::Create(
+          0., CSSPrimitiveValue::UnitType::kPercentage);
+    }
+    if ((horizontal && ConsumeIdent<CSSValueID::kRight>(args)) ||
+        (!horizontal && ConsumeIdent<CSSValueID::kBottom>(args))) {
+      return CSSNumericLiteralValue::Create(
+          100., CSSPrimitiveValue::UnitType::kPercentage);
+    }
+    if (ConsumeIdent<CSSValueID::kCenter>(args)) {
+      return CSSNumericLiteralValue::Create(
+          50., CSSPrimitiveValue::UnitType::kPercentage);
+    }
+    return nullptr;
+  }
+  CSSPrimitiveValue* result = ConsumePercent(args, context, kValueRangeAll);
+  if (!result)
+    result = ConsumeNumber(args, context, kValueRangeAll);
+  return result;
+}
+
+// Used to parse colors for -webkit-gradient(...).
+static CSSValue* ConsumeDeprecatedGradientStopColor(
+    CSSParserTokenRange& args,
+    const CSSParserContext& context) {
+  if (args.Peek().Id() == CSSValueID::kCurrentcolor)
+    return nullptr;
+  return ConsumeColor(args, context);
+}
+
+static bool ConsumeDeprecatedGradientColorStop(
+    CSSParserTokenRange& range,
+    cssvalue::CSSGradientColorStop& stop,
+    const CSSParserContext& context) {
+  CSSValueID id = range.Peek().FunctionId();
+  if (id != CSSValueID::kFrom && id != CSSValueID::kTo &&
+      id != CSSValueID::kColorStop)
+    return false;
+
+  CSSParserTokenRange args = ConsumeFunction(range);
+  double position;
+  if (id == CSSValueID::kFrom || id == CSSValueID::kTo) {
+    position = (id == CSSValueID::kFrom) ? 0 : 1;
+  } else {
+    DCHECK(id == CSSValueID::kColorStop);
+    if (CSSPrimitiveValue* percent_value =
+            ConsumePercent(args, context, kValueRangeAll))
+      position = percent_value->GetDoubleValue() / 100.0;
+    else if (!ConsumeNumberRaw(args, context, position))
+      return false;
+
+    if (!ConsumeCommaIncludingWhitespace(args))
+      return false;
+  }
+
+  stop.offset_ = CSSNumericLiteralValue::Create(
+      position, CSSPrimitiveValue::UnitType::kNumber);
+  stop.color_ = ConsumeDeprecatedGradientStopColor(args, context);
+  return stop.color_ && args.AtEnd();
+}
+
+static CSSValue* ConsumeDeprecatedGradient(CSSParserTokenRange& args,
+                                           const CSSParserContext& context) {
+  CSSValueID id = args.ConsumeIncludingWhitespace().Id();
+  if (id != CSSValueID::kRadial && id != CSSValueID::kLinear)
+    return nullptr;
+
+  if (!ConsumeCommaIncludingWhitespace(args))
+    return nullptr;
+
+  const CSSPrimitiveValue* first_x =
+      ConsumeDeprecatedGradientPoint(args, context, true);
+  if (!first_x)
+    return nullptr;
+  const CSSPrimitiveValue* first_y =
+      ConsumeDeprecatedGradientPoint(args, context, false);
+  if (!first_y)
+    return nullptr;
+  if (!ConsumeCommaIncludingWhitespace(args))
+    return nullptr;
+
+  // For radial gradients only, we now expect a numeric radius.
+  const CSSPrimitiveValue* first_radius = nullptr;
+  if (id == CSSValueID::kRadial) {
+    first_radius = ConsumeNumber(args, context, kValueRangeNonNegative);
+    if (!first_radius || !ConsumeCommaIncludingWhitespace(args))
+      return nullptr;
+  }
+
+  const CSSPrimitiveValue* second_x =
+      ConsumeDeprecatedGradientPoint(args, context, true);
+  if (!second_x)
+    return nullptr;
+  const CSSPrimitiveValue* second_y =
+      ConsumeDeprecatedGradientPoint(args, context, false);
+  if (!second_y)
+    return nullptr;
+
+  // For radial gradients only, we now expect the second radius.
+  const CSSPrimitiveValue* second_radius = nullptr;
+  if (id == CSSValueID::kRadial) {
+    if (!ConsumeCommaIncludingWhitespace(args))
+      return nullptr;
+    second_radius = ConsumeNumber(args, context, kValueRangeNonNegative);
+    if (!second_radius)
+      return nullptr;
+  }
+
+  cssvalue::CSSGradientValue* result;
+  if (id == CSSValueID::kRadial) {
+    result = MakeGarbageCollected<cssvalue::CSSRadialGradientValue>(
+        first_x, first_y, first_radius, second_x, second_y, second_radius,
+        cssvalue::kNonRepeating, cssvalue::kCSSDeprecatedRadialGradient);
+  } else {
+    result = MakeGarbageCollected<cssvalue::CSSLinearGradientValue>(
+        first_x, first_y, second_x, second_y, nullptr, cssvalue::kNonRepeating,
+        cssvalue::kCSSDeprecatedLinearGradient);
+  }
+  cssvalue::CSSGradientColorStop stop;
+  while (ConsumeCommaIncludingWhitespace(args)) {
+    if (!ConsumeDeprecatedGradientColorStop(args, stop, context))
+      return nullptr;
+    result->AddStop(stop);
+  }
+
+  return result;
+}
+
+static CSSPrimitiveValue* ConsumeGradientAngleOrPercent(
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    ValueRange value_range,
+    UnitlessQuirk) {
+  const CSSParserToken& token = range.Peek();
+  if (token.GetType() == kDimensionToken || token.GetType() == kNumberToken) {
+    return ConsumeAngle(range, context, WebFeature::kUnitlessZeroAngleGradient);
+  }
+  if (token.GetType() == kPercentageToken)
+    return ConsumePercent(range, context, value_range);
+  MathFunctionParser math_parser(range, context, value_range);
+  if (const CSSMathFunctionValue* calculation = math_parser.Value()) {
+    CalculationCategory category = calculation->Category();
+    // TODO(fs): Add and support kCalcPercentAngle?
+    if (category == kCalcAngle || category == kCalcPercent)
+      return math_parser.ConsumeValue();
+  }
+  return nullptr;
+}
+
+using PositionFunctor = CSSPrimitiveValue* (*)(CSSParserTokenRange&,
+                                               const CSSParserContext&,
+                                               ValueRange,
+                                               UnitlessQuirk);
+
+static bool ConsumeGradientColorStops(CSSParserTokenRange& range,
+                                      const CSSParserContext& context,
+                                      cssvalue::CSSGradientValue* gradient,
+                                      PositionFunctor consume_position_func) {
+  bool supports_color_hints =
+      gradient->GradientType() == cssvalue::kCSSLinearGradient ||
+      gradient->GradientType() == cssvalue::kCSSRadialGradient ||
+      gradient->GradientType() == cssvalue::kCSSConicGradient;
+
+  // The first color stop cannot be a color hint.
+  bool previous_stop_was_color_hint = true;
+  do {
+    cssvalue::CSSGradientColorStop stop;
+    stop.color_ = ConsumeColor(range, context);
+    // Two hints in a row are not allowed.
+    if (!stop.color_ && (!supports_color_hints || previous_stop_was_color_hint))
+      return false;
+    previous_stop_was_color_hint = !stop.color_;
+    stop.offset_ = consume_position_func(range, context, kValueRangeAll,
+                                         UnitlessQuirk::kForbid);
+    if (!stop.color_ && !stop.offset_)
+      return false;
+    gradient->AddStop(stop);
+
+    if (!stop.color_ || !stop.offset_)
+      continue;
+
+    // Optional second position.
+    stop.offset_ = consume_position_func(range, context, kValueRangeAll,
+                                         UnitlessQuirk::kForbid);
+    if (stop.offset_)
+      gradient->AddStop(stop);
+  } while (ConsumeCommaIncludingWhitespace(range));
+
+  // The last color stop cannot be a color hint.
+  if (previous_stop_was_color_hint)
+    return false;
+
+  // Must have 2 or more stops to be valid.
+  return gradient->StopCount() >= 2;
+}
+
+static CSSValue* ConsumeDeprecatedRadialGradient(
+    CSSParserTokenRange& args,
+    const CSSParserContext& context,
+    cssvalue::CSSGradientRepeat repeating) {
+  CSSValue* center_x = nullptr;
+  CSSValue* center_y = nullptr;
+  ConsumeOneOrTwoValuedPosition(args, context, UnitlessQuirk::kForbid, center_x,
+                                center_y);
+  if ((center_x || center_y) && !ConsumeCommaIncludingWhitespace(args))
+    return nullptr;
+
+  const CSSIdentifierValue* shape =
+      ConsumeIdent<CSSValueID::kCircle, CSSValueID::kEllipse>(args);
+  const CSSIdentifierValue* size_keyword =
+      ConsumeIdent<CSSValueID::kClosestSide, CSSValueID::kClosestCorner,
+                   CSSValueID::kFarthestSide, CSSValueID::kFarthestCorner,
+                   CSSValueID::kContain, CSSValueID::kCover>(args);
+  if (!shape)
+    shape = ConsumeIdent<CSSValueID::kCircle, CSSValueID::kEllipse>(args);
+
+  // Or, two lengths or percentages
+  const CSSPrimitiveValue* horizontal_size = nullptr;
+  const CSSPrimitiveValue* vertical_size = nullptr;
+  if (!shape && !size_keyword) {
+    horizontal_size =
+        ConsumeLengthOrPercent(args, context, kValueRangeNonNegative);
+    if (horizontal_size) {
+      vertical_size =
+          ConsumeLengthOrPercent(args, context, kValueRangeNonNegative);
+      if (!vertical_size)
+        return nullptr;
+      ConsumeCommaIncludingWhitespace(args);
+    }
+  } else {
+    ConsumeCommaIncludingWhitespace(args);
+  }
+
+  cssvalue::CSSGradientValue* result =
+      MakeGarbageCollected<cssvalue::CSSRadialGradientValue>(
+          center_x, center_y, shape, size_keyword, horizontal_size,
+          vertical_size, repeating, cssvalue::kCSSPrefixedRadialGradient);
+  return ConsumeGradientColorStops(args, context, result,
+                                   ConsumeGradientLengthOrPercent)
+             ? result
+             : nullptr;
+}
+
+static CSSValue* ConsumeRadialGradient(CSSParserTokenRange& args,
+                                       const CSSParserContext& context,
+                                       cssvalue::CSSGradientRepeat repeating) {
+  const CSSIdentifierValue* shape = nullptr;
+  const CSSIdentifierValue* size_keyword = nullptr;
+  const CSSPrimitiveValue* horizontal_size = nullptr;
+  const CSSPrimitiveValue* vertical_size = nullptr;
+
+  // First part of grammar, the size/shape clause:
+  // [ circle || <length> ] |
+  // [ ellipse || [ <length> | <percentage> ]{2} ] |
+  // [ [ circle | ellipse] || <size-keyword> ]
+  for (int i = 0; i < 3; ++i) {
+    if (args.Peek().GetType() == kIdentToken) {
+      CSSValueID id = args.Peek().Id();
+      if (id == CSSValueID::kCircle || id == CSSValueID::kEllipse) {
+        if (shape)
+          return nullptr;
+        shape = ConsumeIdent(args);
+      } else if (id == CSSValueID::kClosestSide ||
+                 id == CSSValueID::kClosestCorner ||
+                 id == CSSValueID::kFarthestSide ||
+                 id == CSSValueID::kFarthestCorner) {
+        if (size_keyword)
+          return nullptr;
+        size_keyword = ConsumeIdent(args);
+      } else {
+        break;
+      }
+    } else {
+      CSSPrimitiveValue* center =
+          ConsumeLengthOrPercent(args, context, kValueRangeNonNegative);
+      if (!center)
+        break;
+      if (horizontal_size)
+        return nullptr;
+      horizontal_size = center;
+      center = ConsumeLengthOrPercent(args, context, kValueRangeNonNegative);
+      if (center) {
+        vertical_size = center;
+        ++i;
+      }
+    }
+  }
+
+  // You can specify size as a keyword or a length/percentage, not both.
+  if (size_keyword && horizontal_size)
+    return nullptr;
+  // Circles must have 0 or 1 lengths.
+  if (shape && shape->GetValueID() == CSSValueID::kCircle && vertical_size)
+    return nullptr;
+  // Ellipses must have 0 or 2 length/percentages.
+  if (shape && shape->GetValueID() == CSSValueID::kEllipse && horizontal_size &&
+      !vertical_size) {
+    return nullptr;
+  }
+  // If there's only one size, it must be a length.
+  if (!vertical_size && horizontal_size && horizontal_size->IsPercentage())
+    return nullptr;
+  if ((horizontal_size &&
+       horizontal_size->IsCalculatedPercentageWithLength()) ||
+      (vertical_size && vertical_size->IsCalculatedPercentageWithLength())) {
+    return nullptr;
+  }
+
+  CSSValue* center_x = nullptr;
+  CSSValue* center_y = nullptr;
+  if (args.Peek().Id() == CSSValueID::kAt) {
+    args.ConsumeIncludingWhitespace();
+    ConsumePosition(args, context, UnitlessQuirk::kForbid,
+                    base::Optional<WebFeature>(), center_x, center_y);
+    if (!(center_x && center_y))
+      return nullptr;
+    // Right now, CSS radial gradients have the same start and end centers.
+  }
+
+  if ((shape || size_keyword || horizontal_size || center_x || center_y) &&
+      !ConsumeCommaIncludingWhitespace(args)) {
+    return nullptr;
+  }
+
+  cssvalue::CSSGradientValue* result =
+      MakeGarbageCollected<cssvalue::CSSRadialGradientValue>(
+          center_x, center_y, shape, size_keyword, horizontal_size,
+          vertical_size, repeating, cssvalue::kCSSRadialGradient);
+  return ConsumeGradientColorStops(args, context, result,
+                                   ConsumeGradientLengthOrPercent)
+             ? result
+             : nullptr;
+}
+
+static CSSValue* ConsumeLinearGradient(
+    CSSParserTokenRange& args,
+    const CSSParserContext& context,
+    cssvalue::CSSGradientRepeat repeating,
+    cssvalue::CSSGradientType gradient_type) {
+  bool expect_comma = true;
+  const CSSPrimitiveValue* angle =
+      ConsumeAngle(args, context, WebFeature::kUnitlessZeroAngleGradient);
+  const CSSIdentifierValue* end_x = nullptr;
+  const CSSIdentifierValue* end_y = nullptr;
+  if (!angle) {
+    if (gradient_type == cssvalue::kCSSPrefixedLinearGradient ||
+        ConsumeIdent<CSSValueID::kTo>(args)) {
+      end_x = ConsumeIdent<CSSValueID::kLeft, CSSValueID::kRight>(args);
+      end_y = ConsumeIdent<CSSValueID::kBottom, CSSValueID::kTop>(args);
+      if (!end_x && !end_y) {
+        if (gradient_type == cssvalue::kCSSLinearGradient)
+          return nullptr;
+        end_y = CSSIdentifierValue::Create(CSSValueID::kTop);
+        expect_comma = false;
+      } else if (!end_x) {
+        end_x = ConsumeIdent<CSSValueID::kLeft, CSSValueID::kRight>(args);
+      }
+    } else {
+      expect_comma = false;
+    }
+  }
+
+  if (expect_comma && !ConsumeCommaIncludingWhitespace(args))
+    return nullptr;
+
+  cssvalue::CSSGradientValue* result =
+      MakeGarbageCollected<cssvalue::CSSLinearGradientValue>(
+          end_x, end_y, nullptr, nullptr, angle, repeating, gradient_type);
+  return ConsumeGradientColorStops(args, context, result,
+                                   ConsumeGradientLengthOrPercent)
+             ? result
+             : nullptr;
+}
+
+static CSSValue* ConsumeConicGradient(CSSParserTokenRange& args,
+                                      const CSSParserContext& context,
+                                      cssvalue::CSSGradientRepeat repeating) {
+  const CSSPrimitiveValue* from_angle = nullptr;
+  if (ConsumeIdent<CSSValueID::kFrom>(args)) {
+    if (!(from_angle = ConsumeAngle(args, context,
+                                    WebFeature::kUnitlessZeroAngleGradient)))
+      return nullptr;
+  }
+
+  CSSValue* center_x = nullptr;
+  CSSValue* center_y = nullptr;
+  if (ConsumeIdent<CSSValueID::kAt>(args)) {
+    if (!ConsumePosition(args, context, UnitlessQuirk::kForbid,
+                         base::Optional<WebFeature>(), center_x, center_y))
+      return nullptr;
+  }
+
+  // Comma separator required when fromAngle or position is present.
+  if ((from_angle || center_x || center_y) &&
+      !ConsumeCommaIncludingWhitespace(args)) {
+    return nullptr;
+  }
+
+  auto* result = MakeGarbageCollected<cssvalue::CSSConicGradientValue>(
+      center_x, center_y, from_angle, repeating);
+  return ConsumeGradientColorStops(args, context, result,
+                                   ConsumeGradientAngleOrPercent)
+             ? result
+             : nullptr;
+}
+
+CSSValue* ConsumeImageOrNone(CSSParserTokenRange& range,
+                             const CSSParserContext& context) {
+  if (range.Peek().Id() == CSSValueID::kNone)
+    return ConsumeIdent(range);
+  return ConsumeImage(range, context);
+}
+
+CSSValue* ConsumeAxis(CSSParserTokenRange& range,
+                      const CSSParserContext& context) {
+  CSSValueID axis_id = range.Peek().Id();
+  if (axis_id == CSSValueID::kX || axis_id == CSSValueID::kY ||
+      axis_id == CSSValueID::kZ) {
+    ConsumeIdent(range);
+    return MakeGarbageCollected<cssvalue::CSSAxisValue>(axis_id);
+  }
+
+  CSSValue* x_dimension = ConsumeNumber(range, context, kValueRangeAll);
+  CSSValue* y_dimension = ConsumeNumber(range, context, kValueRangeAll);
+  CSSValue* z_dimension = ConsumeNumber(range, context, kValueRangeAll);
+  if (!x_dimension || !y_dimension || !z_dimension)
+    return nullptr;
+  double x = To<CSSPrimitiveValue>(x_dimension)->GetDoubleValue();
+  double y = To<CSSPrimitiveValue>(y_dimension)->GetDoubleValue();
+  double z = To<CSSPrimitiveValue>(z_dimension)->GetDoubleValue();
+  return MakeGarbageCollected<cssvalue::CSSAxisValue>(x, y, z);
+}
+
+static CSSValue* ConsumeCrossFade(CSSParserTokenRange& args,
+                                  const CSSParserContext& context) {
+  CSSValue* from_image_value = ConsumeImageOrNone(args, context);
+  if (!from_image_value || !ConsumeCommaIncludingWhitespace(args))
+    return nullptr;
+  CSSValue* to_image_value = ConsumeImageOrNone(args, context);
+  if (!to_image_value || !ConsumeCommaIncludingWhitespace(args))
+    return nullptr;
+
+  CSSPrimitiveValue* percentage = nullptr;
+  if (CSSPrimitiveValue* percent_value =
+          ConsumePercent(args, context, kValueRangeAll)) {
+    percentage = CSSNumericLiteralValue::Create(
+        clampTo<double>(percent_value->GetDoubleValue() / 100.0, 0, 1),
+        CSSPrimitiveValue::UnitType::kNumber);
+  } else if (CSSPrimitiveValue* number_value =
+                 ConsumeNumber(args, context, kValueRangeAll)) {
+    percentage = CSSNumericLiteralValue::Create(
+        clampTo<double>(number_value->GetDoubleValue(), 0, 1),
+        CSSPrimitiveValue::UnitType::kNumber);
+  }
+
+  if (!percentage)
+    return nullptr;
+  return MakeGarbageCollected<cssvalue::CSSCrossfadeValue>(
+      from_image_value, to_image_value, percentage);
+}
+
+static CSSValue* ConsumePaint(CSSParserTokenRange& args,
+                              const CSSParserContext& context) {
+  const CSSParserToken& name_token = args.ConsumeIncludingWhitespace();
+  CSSCustomIdentValue* name = ConsumeCustomIdentWithToken(name_token, context);
+  if (!name)
+    return nullptr;
+
+  if (args.AtEnd())
+    return MakeGarbageCollected<CSSPaintValue>(name);
+
+  if (!RuntimeEnabledFeatures::CSSPaintAPIArgumentsEnabled()) {
+    // Arguments not enabled, but exists. Invalid.
+    return nullptr;
+  }
+
+  // Begin parse paint arguments.
+  if (!ConsumeCommaIncludingWhitespace(args))
+    return nullptr;
+
+  // Consume arguments.
+  // TODO(renjieliu): We may want to optimize the implementation by resolve
+  // variables early if paint function is registered.
+  Vector<CSSParserToken> argument_tokens;
+  Vector<scoped_refptr<CSSVariableData>> variable_data;
+  while (!args.AtEnd()) {
+    if (args.Peek().GetType() != kCommaToken) {
+      argument_tokens.AppendVector(ConsumeFunctionArgsOrNot(args));
+    } else {
+      if (!AddCSSPaintArgument(argument_tokens, &variable_data, context))
+        return nullptr;
+      argument_tokens.clear();
+      if (!ConsumeCommaIncludingWhitespace(args))
+        return nullptr;
+    }
+  }
+  if (!AddCSSPaintArgument(argument_tokens, &variable_data, context))
+    return nullptr;
+
+  return MakeGarbageCollected<CSSPaintValue>(name, variable_data);
+}
+
+static CSSValue* ConsumeGeneratedImage(CSSParserTokenRange& range,
+                                       const CSSParserContext& context) {
+  CSSValueID id = range.Peek().FunctionId();
+  CSSParserTokenRange range_copy = range;
+  CSSParserTokenRange args = ConsumeFunction(range_copy);
+  CSSValue* result = nullptr;
+  if (id == CSSValueID::kRadialGradient) {
+    result = ConsumeRadialGradient(args, context, cssvalue::kNonRepeating);
+  } else if (id == CSSValueID::kRepeatingRadialGradient) {
+    result = ConsumeRadialGradient(args, context, cssvalue::kRepeating);
+  } else if (id == CSSValueID::kWebkitLinearGradient) {
+    context.Count(WebFeature::kDeprecatedWebKitLinearGradient);
+    result = ConsumeLinearGradient(args, context, cssvalue::kNonRepeating,
+                                   cssvalue::kCSSPrefixedLinearGradient);
+  } else if (id == CSSValueID::kWebkitRepeatingLinearGradient) {
+    context.Count(WebFeature::kDeprecatedWebKitRepeatingLinearGradient);
+    result = ConsumeLinearGradient(args, context, cssvalue::kRepeating,
+                                   cssvalue::kCSSPrefixedLinearGradient);
+  } else if (id == CSSValueID::kRepeatingLinearGradient) {
+    result = ConsumeLinearGradient(args, context, cssvalue::kRepeating,
+                                   cssvalue::kCSSLinearGradient);
+  } else if (id == CSSValueID::kLinearGradient) {
+    result = ConsumeLinearGradient(args, context, cssvalue::kNonRepeating,
+                                   cssvalue::kCSSLinearGradient);
+  } else if (id == CSSValueID::kWebkitGradient) {
+    context.Count(WebFeature::kDeprecatedWebKitGradient);
+    result = ConsumeDeprecatedGradient(args, context);
+  } else if (id == CSSValueID::kWebkitRadialGradient) {
+    context.Count(WebFeature::kDeprecatedWebKitRadialGradient);
+    result =
+        ConsumeDeprecatedRadialGradient(args, context, cssvalue::kNonRepeating);
+  } else if (id == CSSValueID::kWebkitRepeatingRadialGradient) {
+    context.Count(WebFeature::kDeprecatedWebKitRepeatingRadialGradient);
+    result =
+        ConsumeDeprecatedRadialGradient(args, context, cssvalue::kRepeating);
+  } else if (id == CSSValueID::kConicGradient) {
+    result = ConsumeConicGradient(args, context, cssvalue::kNonRepeating);
+  } else if (id == CSSValueID::kRepeatingConicGradient) {
+    result = ConsumeConicGradient(args, context, cssvalue::kRepeating);
+  } else if (id == CSSValueID::kWebkitCrossFade) {
+    result = ConsumeCrossFade(args, context);
+  } else if (id == CSSValueID::kPaint) {
+    result = context.IsSecureContext() ? ConsumePaint(args, context) : nullptr;
+  }
+  if (!result || !args.AtEnd())
+    return nullptr;
+
+  WebFeature feature;
+  if (id == CSSValueID::kWebkitCrossFade)
+    feature = WebFeature::kWebkitCrossFade;
+  else if (id == CSSValueID::kPaint)
+    feature = WebFeature::kCSSPaintFunction;
+  else
+    feature = WebFeature::kCSSGradient;
+  context.Count(feature);
+
+  range = range_copy;
+  return result;
+}
+
+static CSSValue* CreateCSSImageValueWithReferrer(
+    const AtomicString& raw_value,
+    const CSSParserContext& context) {
+  CSSValue* image_value = MakeGarbageCollected<CSSImageValue>(
+      raw_value, context.CompleteURL(raw_value), context.GetReferrer(),
+      context.IsOriginClean() ? OriginClean::kTrue : OriginClean::kFalse,
+      context.IsAdRelated());
+  return image_value;
+}
+
+static CSSValue* ConsumeImageSet(CSSParserTokenRange& range,
+                                 const CSSParserContext& context) {
+  CSSParserTokenRange range_copy = range;
+  CSSParserTokenRange args = ConsumeFunction(range_copy);
+  auto* image_set = MakeGarbageCollected<CSSImageSetValue>(context.Mode());
+  do {
+    AtomicString url_value =
+        ConsumeUrlAsStringView(args, context).ToAtomicString();
+    if (url_value.IsNull())
+      return nullptr;
+
+    CSSValue* image = CreateCSSImageValueWithReferrer(url_value, context);
+    image_set->Append(*image);
+
+    const CSSParserToken& token = args.ConsumeIncludingWhitespace();
+    if (token.GetType() != kDimensionToken)
+      return nullptr;
+    if (token.Value() != "x")
+      return nullptr;
+    DCHECK(token.GetUnitType() == CSSPrimitiveValue::UnitType::kDotsPerPixel);
+    double image_scale_factor = token.NumericValue();
+    if (image_scale_factor <= 0)
+      return nullptr;
+    image_set->Append(*CSSNumericLiteralValue::Create(
+        image_scale_factor, CSSPrimitiveValue::UnitType::kNumber));
+  } while (ConsumeCommaIncludingWhitespace(args));
+  if (!args.AtEnd())
+    return nullptr;
+  range = range_copy;
+  return image_set;
+}
+
+static bool IsGeneratedImage(CSSValueID id) {
+  return id == CSSValueID::kLinearGradient ||
+         id == CSSValueID::kRadialGradient ||
+         id == CSSValueID::kConicGradient ||
+         id == CSSValueID::kRepeatingLinearGradient ||
+         id == CSSValueID::kRepeatingRadialGradient ||
+         id == CSSValueID::kRepeatingConicGradient ||
+         id == CSSValueID::kWebkitLinearGradient ||
+         id == CSSValueID::kWebkitRadialGradient ||
+         id == CSSValueID::kWebkitRepeatingLinearGradient ||
+         id == CSSValueID::kWebkitRepeatingRadialGradient ||
+         id == CSSValueID::kWebkitGradient ||
+         id == CSSValueID::kWebkitCrossFade || id == CSSValueID::kPaint;
+}
+
+CSSValue* ConsumeImage(CSSParserTokenRange& range,
+                       const CSSParserContext& context,
+                       ConsumeGeneratedImagePolicy generated_image) {
+  AtomicString uri = ConsumeUrlAsStringView(range, context).ToAtomicString();
+  if (!uri.IsNull())
+    return CreateCSSImageValueWithReferrer(uri, context);
+  if (range.Peek().GetType() == kFunctionToken) {
+    CSSValueID id = range.Peek().FunctionId();
+    if (id == CSSValueID::kWebkitImageSet)
+      return ConsumeImageSet(range, context);
+    if (generated_image == ConsumeGeneratedImagePolicy::kAllow &&
+        IsGeneratedImage(id)) {
+      return ConsumeGeneratedImage(range, context);
+    }
+    return ConsumeInternalLightDark(ConsumeImageOrNone, range, context);
+  }
+  return nullptr;
+}
+
+// https://drafts.csswg.org/css-shapes-1/#typedef-shape-box
+CSSIdentifierValue* ConsumeShapeBox(CSSParserTokenRange& range) {
+  return ConsumeIdent<CSSValueID::kContentBox, CSSValueID::kPaddingBox,
+                      CSSValueID::kBorderBox, CSSValueID::kMarginBox>(range);
+}
+
+void AddProperty(CSSPropertyID resolved_property,
+                 CSSPropertyID current_shorthand,
+                 const CSSValue& value,
+                 bool important,
+                 IsImplicitProperty implicit,
+                 HeapVector<CSSPropertyValue, 256>& properties) {
+  DCHECK(!isPropertyAlias(resolved_property));
+  DCHECK(implicit == IsImplicitProperty::kNotImplicit ||
+         implicit == IsImplicitProperty::kImplicit);
+
+  int shorthand_index = 0;
+  bool set_from_shorthand = false;
+
+  if (isValidCSSPropertyID(current_shorthand)) {
+    Vector<StylePropertyShorthand, 4> shorthands;
+    getMatchingShorthandsForLonghand(resolved_property, &shorthands);
+    set_from_shorthand = true;
+    if (shorthands.size() > 1) {
+      shorthand_index =
+          indexOfShorthandForLonghand(current_shorthand, shorthands);
+    }
+  }
+
+  properties.push_back(CSSPropertyValue(
+      CSSProperty::Get(resolved_property), value, important, set_from_shorthand,
+      shorthand_index, implicit == IsImplicitProperty::kImplicit));
+}
+
+CSSValue* ConsumeTransformValue(CSSParserTokenRange& range,
+                                const CSSParserContext& context) {
+  bool use_legacy_parsing = false;
+  return ConsumeTransformValue(range, context, use_legacy_parsing);
+}
+
+CSSValue* ConsumeTransformList(CSSParserTokenRange& range,
+                               const CSSParserContext& context) {
+  return ConsumeTransformList(range, context, CSSParserLocalContext());
+}
+
+CSSValue* ConsumeFilterFunctionList(CSSParserTokenRange& range,
+                                    const CSSParserContext& context) {
+  if (range.Peek().Id() == CSSValueID::kNone)
+    return ConsumeIdent(range);
+
+  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
+  do {
+    CSSValue* filter_value = ConsumeUrl(range, context);
+    if (!filter_value) {
+      filter_value = ConsumeFilterFunction(range, context);
+      if (!filter_value)
+        return nullptr;
+    }
+    list->Append(*filter_value);
+  } while (!range.AtEnd());
+  return list;
+}
+
+void CountKeywordOnlyPropertyUsage(CSSPropertyID property,
+                                   const CSSParserContext& context,
+                                   CSSValueID value_id) {
+  if (!context.IsUseCounterRecordingEnabled())
+    return;
+  switch (property) {
+    case CSSPropertyID::kAppearance:
+      if (value_id == CSSValueID::kInnerSpinButton ||
+          value_id == CSSValueID::kMediaSlider ||
+          value_id == CSSValueID::kMediaSliderthumb ||
+          value_id == CSSValueID::kMediaVolumeSlider ||
+          value_id == CSSValueID::kMediaVolumeSliderthumb ||
+          value_id == CSSValueID::kSliderVertical ||
+          value_id == CSSValueID::kSliderthumbHorizontal ||
+          value_id == CSSValueID::kSliderthumbVertical ||
+          value_id == CSSValueID::kSearchfieldCancelButton) {
+        if (const auto* document = context.GetDocument()) {
+          document->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+              mojom::blink::ConsoleMessageSource::kOther,
+              mojom::blink::ConsoleMessageLevel::kWarning,
+              String("The keyword '") + getValueName(value_id) +
+                  "' specified to an 'appearance' property is not "
+                  "standardized. It will be removed in the future."));
+        }
+      }
+      FALLTHROUGH;
+      // This function distinguishes 'appearance' and '-webkit-appearance'
+      // though other property aliases are handles as their aliased properties.
+      // See Appearance::ParseSingleValue().
+    case CSSPropertyID::kAliasWebkitAppearance: {
+      WebFeature feature;
+      if (value_id == CSSValueID::kNone) {
+        feature = WebFeature::kCSSValueAppearanceNone;
+      } else {
+        feature = WebFeature::kCSSValueAppearanceNotNone;
+        if (value_id == CSSValueID::kButton)
+          feature = WebFeature::kCSSValueAppearanceButton;
+        else if (value_id == CSSValueID::kCheckbox)
+          feature = WebFeature::kCSSValueAppearanceCheckbox;
+        else if (value_id == CSSValueID::kInnerSpinButton)
+          feature = WebFeature::kCSSValueAppearanceInnerSpinButton;
+        else if (value_id == CSSValueID::kMenulist)
+          feature = WebFeature::kCSSValueAppearanceMenulist;
+        else if (value_id == CSSValueID::kMenulistButton)
+          feature = WebFeature::kCSSValueAppearanceMenulistButton;
+        else if (value_id == CSSValueID::kMeter)
+          feature = WebFeature::kCSSValueAppearanceMeter;
+        else if (value_id == CSSValueID::kListbox)
+          feature = WebFeature::kCSSValueAppearanceListbox;
+        else if (value_id == CSSValueID::kProgressBar)
+          feature = WebFeature::kCSSValueAppearanceProgressBar;
+        else if (value_id == CSSValueID::kPushButton)
+          feature = WebFeature::kCSSValueAppearancePushButton;
+        else if (value_id == CSSValueID::kRadio)
+          feature = WebFeature::kCSSValueAppearanceRadio;
+        else if (value_id == CSSValueID::kSearchfieldCancelButton)
+          feature = WebFeature::kCSSValueAppearanceSearchCancel;
+        else if (value_id == CSSValueID::kSquareButton)
+          feature = WebFeature::kCSSValueAppearanceSquareButton;
+        else if (value_id == CSSValueID::kSearchfield)
+          feature = WebFeature::kCSSValueAppearanceSearchField;
+        else if (value_id == CSSValueID::kTextarea)
+          feature = WebFeature::kCSSValueAppearanceTextarea;
+        else if (value_id == CSSValueID::kTextfield)
+          feature = WebFeature::kCSSValueAppearanceTextField;
+        else
+          feature = WebFeature::kCSSValueAppearanceOthers;
+      }
+      context.Count(feature);
+      break;
+    }
+
+    case CSSPropertyID::kWebkitUserModify: {
+      switch (value_id) {
+        case CSSValueID::kReadOnly:
+          context.Count(WebFeature::kCSSValueUserModifyReadOnly);
+          break;
+        case CSSValueID::kReadWrite:
+          context.Count(WebFeature::kCSSValueUserModifyReadWrite);
+          break;
+        case CSSValueID::kReadWritePlaintextOnly:
+          context.Count(WebFeature::kCSSValueUserModifyReadWritePlaintextOnly);
+          break;
+        default:
+          NOTREACHED();
+      }
+      break;
+    }
+    case CSSPropertyID::kDisplay:
+      if (value_id == CSSValueID::kContents)
+        context.Count(WebFeature::kCSSValueDisplayContents);
+      break;
+    case CSSPropertyID::kOverflowX:
+    case CSSPropertyID::kOverflowY:
+      if (value_id == CSSValueID::kOverlay)
+        context.Count(WebFeature::kCSSValueOverflowOverlay);
+      break;
+    default:
+      break;
+  }
+}
+
+const CSSValue* ParseLonghand(CSSPropertyID unresolved_property,
+                              CSSPropertyID current_shorthand,
+                              const CSSParserContext& context,
+                              CSSParserTokenRange& range) {
+  CSSPropertyID property_id = resolveCSSPropertyID(unresolved_property);
+  DCHECK(!CSSProperty::Get(property_id).IsShorthand());
+  if (CSSParserFastPaths::IsKeywordPropertyID(property_id)) {
+    if (CSSParserFastPaths::IsValidKeywordPropertyAndValue(
+            property_id, range.Peek().Id(), context.Mode())) {
+      CountKeywordOnlyPropertyUsage(property_id, context, range.Peek().Id());
+      return ConsumeIdent(range);
+    }
+
+    // Some properties need to fallback onto the regular parser.
+    if (!CSSParserFastPaths::IsPartialKeywordPropertyID(property_id))
+      return nullptr;
+  }
+
+  const auto local_context =
+      CSSParserLocalContext()
+          .WithAliasParsing(isPropertyAlias(unresolved_property))
+          .WithCurrentShorthand(current_shorthand);
+
+  const CSSValue* result = To<Longhand>(CSSProperty::Get(property_id))
+                               .ParseSingleValue(range, context, local_context);
+  return result;
+}
+
+bool ConsumeShorthandVia2Longhands(
+    const StylePropertyShorthand& shorthand,
+    bool important,
+    const CSSParserContext& context,
+    CSSParserTokenRange& range,
+    HeapVector<CSSPropertyValue, 256>& properties) {
+  DCHECK_EQ(shorthand.length(), 2u);
+  const CSSProperty** longhands = shorthand.properties();
+
+  const CSSValue* start =
+      ParseLonghand(longhands[0]->PropertyID(), shorthand.id(), context, range);
+
+  if (!start)
+    return false;
+
+  const CSSValue* end =
+      ParseLonghand(longhands[1]->PropertyID(), shorthand.id(), context, range);
+
+  if (shorthand.id() == CSSPropertyID::kOverflow && start && end) {
+    context.Count(WebFeature::kTwoValuedOverflow);
+  }
+
+  if (!end)
+    end = start;
+  AddProperty(longhands[0]->PropertyID(), shorthand.id(), *start, important,
+              IsImplicitProperty::kNotImplicit, properties);
+  AddProperty(longhands[1]->PropertyID(), shorthand.id(), *end, important,
+              IsImplicitProperty::kNotImplicit, properties);
+
+  return range.AtEnd();
+}
+
+bool ConsumeShorthandVia4Longhands(
+    const StylePropertyShorthand& shorthand,
+    bool important,
+    const CSSParserContext& context,
+    CSSParserTokenRange& range,
+    HeapVector<CSSPropertyValue, 256>& properties) {
+  DCHECK_EQ(shorthand.length(), 4u);
+  const CSSProperty** longhands = shorthand.properties();
+  const CSSValue* top =
+      ParseLonghand(longhands[0]->PropertyID(), shorthand.id(), context, range);
+
+  if (!top)
+    return false;
+
+  const CSSValue* right =
+      ParseLonghand(longhands[1]->PropertyID(), shorthand.id(), context, range);
+
+  const CSSValue* bottom = nullptr;
+  const CSSValue* left = nullptr;
+  if (right) {
+    bottom = ParseLonghand(longhands[2]->PropertyID(), shorthand.id(), context,
+                           range);
+    if (bottom) {
+      left = ParseLonghand(longhands[3]->PropertyID(), shorthand.id(), context,
+                           range);
+    }
+  }
+
+  if (!right)
+    right = top;
+  if (!bottom)
+    bottom = top;
+  if (!left)
+    left = right;
+
+  AddProperty(longhands[0]->PropertyID(), shorthand.id(), *top, important,
+              IsImplicitProperty::kNotImplicit, properties);
+  AddProperty(longhands[1]->PropertyID(), shorthand.id(), *right, important,
+              IsImplicitProperty::kNotImplicit, properties);
+  AddProperty(longhands[2]->PropertyID(), shorthand.id(), *bottom, important,
+              IsImplicitProperty::kNotImplicit, properties);
+  AddProperty(longhands[3]->PropertyID(), shorthand.id(), *left, important,
+              IsImplicitProperty::kNotImplicit, properties);
+
+  return range.AtEnd();
+}
+
+bool ConsumeShorthandGreedilyViaLonghands(
+    const StylePropertyShorthand& shorthand,
+    bool important,
+    const CSSParserContext& context,
+    CSSParserTokenRange& range,
+    HeapVector<CSSPropertyValue, 256>& properties) {
+  // Existing shorthands have at most 6 longhands.
+  DCHECK_LE(shorthand.length(), 6u);
+  const CSSValue* longhands[6] = {nullptr, nullptr, nullptr,
+                                  nullptr, nullptr, nullptr};
+  const CSSProperty** shorthand_properties = shorthand.properties();
+  do {
+    bool found_longhand = false;
+    for (size_t i = 0; !found_longhand && i < shorthand.length(); ++i) {
+      if (longhands[i])
+        continue;
+      longhands[i] = ParseLonghand(shorthand_properties[i]->PropertyID(),
+                                   shorthand.id(), context, range);
+
+      if (longhands[i])
+        found_longhand = true;
+    }
+    if (!found_longhand)
+      return false;
+  } while (!range.AtEnd());
+
+  for (size_t i = 0; i < shorthand.length(); ++i) {
+    if (longhands[i]) {
+      AddProperty(shorthand_properties[i]->PropertyID(), shorthand.id(),
+                  *longhands[i], important, IsImplicitProperty::kNotImplicit,
+                  properties);
+    } else {
+      AddProperty(shorthand_properties[i]->PropertyID(), shorthand.id(),
+                  *CSSInitialValue::Create(), important,
+                  IsImplicitProperty::kNotImplicit, properties);
+    }
+  }
+  return true;
+}
+
+void AddExpandedPropertyForValue(
+    CSSPropertyID property,
+    const CSSValue& value,
+    bool important,
+    HeapVector<CSSPropertyValue, 256>& properties) {
+  const StylePropertyShorthand& shorthand = shorthandForProperty(property);
+  unsigned shorthand_length = shorthand.length();
+  DCHECK(shorthand_length);
+  const CSSProperty** longhands = shorthand.properties();
+  for (unsigned i = 0; i < shorthand_length; ++i) {
+    AddProperty(longhands[i]->PropertyID(), property, value, important,
+                IsImplicitProperty::kNotImplicit, properties);
+  }
+}
+
 bool IsBaselineKeyword(CSSValueID id) {
-  return css_property_parser_helpers::IdentMatches<
-      CSSValueID::kFirst, CSSValueID::kLast, CSSValueID::kBaseline>(id);
+  return IdentMatches<CSSValueID::kFirst, CSSValueID::kLast,
+                      CSSValueID::kBaseline>(id);
 }
 
 bool IsSelfPositionKeyword(CSSValueID id) {
-  return css_property_parser_helpers::IdentMatches<
-      CSSValueID::kStart, CSSValueID::kEnd, CSSValueID::kCenter,
-      CSSValueID::kSelfStart, CSSValueID::kSelfEnd, CSSValueID::kFlexStart,
-      CSSValueID::kFlexEnd>(id);
+  return IdentMatches<CSSValueID::kStart, CSSValueID::kEnd, CSSValueID::kCenter,
+                      CSSValueID::kSelfStart, CSSValueID::kSelfEnd,
+                      CSSValueID::kFlexStart, CSSValueID::kFlexEnd>(id);
 }
 
 bool IsSelfPositionOrLeftOrRightKeyword(CSSValueID id) {
@@ -450,9 +2563,8 @@
 }
 
 bool IsContentPositionKeyword(CSSValueID id) {
-  return css_property_parser_helpers::IdentMatches<
-      CSSValueID::kStart, CSSValueID::kEnd, CSSValueID::kCenter,
-      CSSValueID::kFlexStart, CSSValueID::kFlexEnd>(id);
+  return IdentMatches<CSSValueID::kStart, CSSValueID::kEnd, CSSValueID::kCenter,
+                      CSSValueID::kFlexStart, CSSValueID::kFlexEnd>(id);
 }
 
 bool IsContentPositionOrLeftOrRightKeyword(CSSValueID id) {
@@ -466,15 +2578,33 @@
           (id == CSSValueID::kRevert));
 }
 
+// https://drafts.csswg.org/css-values-4/#css-wide-keywords
+bool IsCSSWideKeyword(StringView keyword) {
+  return EqualIgnoringASCIICase(keyword, "initial") ||
+         EqualIgnoringASCIICase(keyword, "inherit") ||
+         EqualIgnoringASCIICase(keyword, "unset") ||
+         (RuntimeEnabledFeatures::CSSRevertEnabled() &&
+          EqualIgnoringASCIICase(keyword, "revert"));
+}
+
+// https://drafts.csswg.org/css-cascade/#default
+bool IsRevertKeyword(StringView keyword) {
+  return EqualIgnoringASCIICase(keyword, "revert");
+}
+
+// https://drafts.csswg.org/css-values-4/#identifier-value
+bool IsDefaultKeyword(StringView keyword) {
+  return EqualIgnoringASCIICase(keyword, "default");
+}
+
 CSSValue* ConsumeScrollOffset(CSSParserTokenRange& range,
                               const CSSParserContext& context) {
   range.ConsumeWhitespace();
-  if (css_property_parser_helpers::IdentMatches<CSSValueID::kAuto>(
-          range.Peek().Id()))
-    return css_property_parser_helpers::ConsumeIdent(range);
+  if (IdentMatches<CSSValueID::kAuto>(range.Peek().Id()))
+    return ConsumeIdent(range);
   CSSParserContext::ParserModeOverridingScope scope(context, kHTMLStandardMode);
-  CSSValue* value = css_property_parser_helpers::ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative);
+  CSSValue* value =
+      ConsumeLengthOrPercent(range, context, kValueRangeNonNegative);
   if (!range.AtEnd())
     return nullptr;
   return value;
@@ -486,7 +2616,7 @@
   DCHECK(is_position_keyword);
   CSSValueID id = range.Peek().Id();
   if (IsAuto(id) || IsNormalOrStretch(id))
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
 
   if (IsBaselineKeyword(id))
     return ConsumeBaselineKeyword(range);
@@ -494,8 +2624,7 @@
   CSSIdentifierValue* overflow_position = ConsumeOverflowPositionKeyword(range);
   if (!is_position_keyword(range.Peek().Id()))
     return nullptr;
-  CSSIdentifierValue* self_position =
-      css_property_parser_helpers::ConsumeIdent(range);
+  CSSIdentifierValue* self_position = ConsumeIdent(range);
   if (overflow_position) {
     return MakeGarbageCollected<CSSValuePair>(
         overflow_position, self_position, CSSValuePair::kDropIdenticalValues);
@@ -508,7 +2637,7 @@
     IsPositionKeyword is_position_keyword) {
   DCHECK(is_position_keyword);
   CSSValueID id = range.Peek().Id();
-  if (css_property_parser_helpers::IdentMatches<CSSValueID::kNormal>(id)) {
+  if (IdentMatches<CSSValueID::kNormal>(id)) {
     return MakeGarbageCollected<cssvalue::CSSContentDistributionValue>(
         CSSValueID::kInvalid, range.ConsumeIncludingWhitespace().Id(),
         CSSValueID::kInvalid);
@@ -544,16 +2673,15 @@
 CSSValue* ConsumeAnimationIterationCount(CSSParserTokenRange& range,
                                          const CSSParserContext& context) {
   if (range.Peek().Id() == CSSValueID::kInfinite)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeNumber(range, context,
-                                                    kValueRangeNonNegative);
+    return ConsumeIdent(range);
+  return ConsumeNumber(range, context, kValueRangeNonNegative);
 }
 
 CSSValue* ConsumeAnimationName(CSSParserTokenRange& range,
                                const CSSParserContext& context,
                                bool allow_quoted_name) {
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
 
   if (allow_quoted_name && range.Peek().GetType() == kStringToken) {
     // Legacy support for strings in prefixed animations.
@@ -566,21 +2694,16 @@
         token.Value().ToAtomicString());
   }
 
-  return css_property_parser_helpers::ConsumeCustomIdent(range, context);
+  return ConsumeCustomIdent(range, context);
 }
 
 CSSValue* ConsumeAnimationTimeline(CSSParserTokenRange& range,
                                    const CSSParserContext& context) {
-  if (auto* value =
-          css_property_parser_helpers::ConsumeIdent<CSSValueID::kNone,
-                                                    CSSValueID::kAuto>(range)) {
+  if (auto* value = ConsumeIdent<CSSValueID::kNone, CSSValueID::kAuto>(range))
     return value;
-  }
-  if (auto* value =
-          css_property_parser_helpers::ConsumeCustomIdent(range, context)) {
+  if (auto* value = ConsumeCustomIdent(range, context))
     return value;
-  }
-  return css_property_parser_helpers::ConsumeString(range);
+  return ConsumeString(range);
 }
 
 CSSValue* ConsumeAnimationTimingFunction(CSSParserTokenRange& range,
@@ -590,7 +2713,7 @@
       id == CSSValueID::kEaseIn || id == CSSValueID::kEaseOut ||
       id == CSSValueID::kEaseInOut || id == CSSValueID::kStepStart ||
       id == CSSValueID::kStepEnd)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
 
   CSSValueID function = range.Peek().FunctionId();
   if (function == CSSValueID::kSteps)
@@ -643,7 +2766,7 @@
       }
       parsed_longhand[i] = false;
     }
-  } while (css_property_parser_helpers::ConsumeCommaIncludingWhitespace(range));
+  } while (ConsumeCommaIncludingWhitespace(range));
 
   return true;
 }
@@ -663,33 +2786,31 @@
 }
 
 CSSValue* ConsumeBackgroundAttachment(CSSParserTokenRange& range) {
-  return css_property_parser_helpers::ConsumeIdent<
-      CSSValueID::kScroll, CSSValueID::kFixed, CSSValueID::kLocal>(range);
+  return ConsumeIdent<CSSValueID::kScroll, CSSValueID::kFixed,
+                      CSSValueID::kLocal>(range);
 }
 
 CSSValue* ConsumeBackgroundBlendMode(CSSParserTokenRange& range) {
   CSSValueID id = range.Peek().Id();
   if (id == CSSValueID::kNormal || id == CSSValueID::kOverlay ||
       (id >= CSSValueID::kMultiply && id <= CSSValueID::kLuminosity))
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
   return nullptr;
 }
 
 CSSValue* ConsumeBackgroundBox(CSSParserTokenRange& range) {
-  return css_property_parser_helpers::ConsumeIdent<
-      CSSValueID::kBorderBox, CSSValueID::kPaddingBox, CSSValueID::kContentBox>(
-      range);
+  return ConsumeIdent<CSSValueID::kBorderBox, CSSValueID::kPaddingBox,
+                      CSSValueID::kContentBox>(range);
 }
 
 CSSValue* ConsumeBackgroundComposite(CSSParserTokenRange& range) {
-  return css_property_parser_helpers::ConsumeIdentRange(
-      range, CSSValueID::kClear, CSSValueID::kPlusLighter);
+  return ConsumeIdentRange(range, CSSValueID::kClear, CSSValueID::kPlusLighter);
 }
 
 CSSValue* ConsumeMaskSourceType(CSSParserTokenRange& range) {
   DCHECK(RuntimeEnabledFeatures::CSSMaskSourceTypeEnabled());
-  return css_property_parser_helpers::ConsumeIdent<
-      CSSValueID::kAuto, CSSValueID::kAlpha, CSSValueID::kLuminance>(range);
+  return ConsumeIdent<CSSValueID::kAuto, CSSValueID::kAlpha,
+                      CSSValueID::kLuminance>(range);
 }
 
 CSSPrimitiveValue* ConsumeLengthOrPercentCountNegative(
@@ -697,8 +2818,7 @@
     const CSSParserContext& context,
     base::Optional<WebFeature> negative_size) {
   CSSPrimitiveValue* result = ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative,
-      css_property_parser_helpers::UnitlessQuirk::kForbid);
+      range, context, kValueRangeNonNegative, UnitlessQuirk::kForbid);
   if (!result && negative_size)
     context.Count(*negative_size);
   return result;
@@ -708,14 +2828,12 @@
                                 const CSSParserContext& context,
                                 base::Optional<WebFeature> negative_size,
                                 ParsingStyle parsing_style) {
-  if (css_property_parser_helpers::IdentMatches<CSSValueID::kContain,
-                                                CSSValueID::kCover>(
+  if (IdentMatches<CSSValueID::kContain, CSSValueID::kCover>(
           range.Peek().Id())) {
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
   }
 
-  CSSValue* horizontal =
-      css_property_parser_helpers::ConsumeIdent<CSSValueID::kAuto>(range);
+  CSSValue* horizontal = ConsumeIdent<CSSValueID::kAuto>(range);
   if (!horizontal) {
     horizontal =
         ConsumeLengthOrPercentCountNegative(range, context, negative_size);
@@ -747,18 +2865,17 @@
     math_value->SetAllowsNegativePercentageReference();
 }
 
-bool ConsumeBackgroundPosition(
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    css_property_parser_helpers::UnitlessQuirk unitless,
-    CSSValue*& result_x,
-    CSSValue*& result_y) {
+bool ConsumeBackgroundPosition(CSSParserTokenRange& range,
+                               const CSSParserContext& context,
+                               UnitlessQuirk unitless,
+                               CSSValue*& result_x,
+                               CSSValue*& result_y) {
   do {
     CSSValue* position_x = nullptr;
     CSSValue* position_y = nullptr;
-    if (!css_property_parser_helpers::ConsumePosition(
-            range, context, unitless,
-            WebFeature::kThreeValuedPositionBackground, position_x, position_y))
+    if (!ConsumePosition(range, context, unitless,
+                         WebFeature::kThreeValuedPositionBackground, position_x,
+                         position_y))
       return false;
     // TODO(crbug.com/825895): So far, 'background-position' is the only
     // property that allows resolving a percentage against a negative value. If
@@ -768,7 +2885,7 @@
     SetAllowsNegativePercentageReference(position_y);
     AddBackgroundValue(result_x, position_x);
     AddBackgroundValue(result_y, position_y);
-  } while (css_property_parser_helpers::ConsumeCommaIncludingWhitespace(range));
+  } while (ConsumeCommaIncludingWhitespace(range));
   return true;
 }
 
@@ -776,12 +2893,12 @@
                                        AllowTextValue allow_text_value) {
   // The values 'border', 'padding' and 'content' are deprecated and do not
   // apply to the version of the property that has the -webkit- prefix removed.
-  if (CSSValue* value = css_property_parser_helpers::ConsumeIdentRange(
-          range, CSSValueID::kBorder, CSSValueID::kPaddingBox))
+  if (CSSValue* value = ConsumeIdentRange(range, CSSValueID::kBorder,
+                                          CSSValueID::kPaddingBox))
     return value;
   if (allow_text_value == AllowTextValue::kAllow &&
       range.Peek().Id() == CSSValueID::kText)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
   return nullptr;
 }
 
@@ -790,18 +2907,17 @@
                              AllowTextValue alias_allow_text_value) {
   // This is legacy behavior that does not match spec, see crbug.com/604023
   if (local_context.UseAliasParsing()) {
-    return css_property_parser_helpers::ConsumeCommaSeparatedList(
-        ConsumePrefixedBackgroundBox, range, alias_allow_text_value);
+    return ConsumeCommaSeparatedList(ConsumePrefixedBackgroundBox, range,
+                                     alias_allow_text_value);
   }
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
-      ConsumeBackgroundBox, range);
+  return ConsumeCommaSeparatedList(ConsumeBackgroundBox, range);
 }
 
 CSSValue* ParseBackgroundOrMaskSize(CSSParserTokenRange& range,
                                     const CSSParserContext& context,
                                     const CSSParserLocalContext& local_context,
                                     base::Optional<WebFeature> negative_size) {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
+  return ConsumeCommaSeparatedList(
       ConsumeBackgroundSize, range, context, negative_size,
       local_context.UseAliasParsing() ? ParsingStyle::kLegacy
                                       : ParsingStyle::kNotLegacy);
@@ -821,7 +2937,7 @@
       return ConsumeBackgroundBox(range);
     case CSSPropertyID::kBackgroundImage:
     case CSSPropertyID::kWebkitMaskImage:
-      return css_property_parser_helpers::ConsumeImageOrNone(range, context);
+      return ConsumeImageOrNone(range, context);
     case CSSPropertyID::kBackgroundPositionX:
     case CSSPropertyID::kWebkitMaskPositionX:
       return ConsumePositionLonghand<CSSValueID::kLeft, CSSValueID::kRight>(
@@ -839,7 +2955,7 @@
                                    WebFeature::kNegativeMaskSize,
                                    ParsingStyle::kNotLegacy);
     case CSSPropertyID::kBackgroundColor:
-      return css_property_parser_helpers::ConsumeColor(range, context);
+      return ConsumeColor(range, context);
     case CSSPropertyID::kWebkitMaskClip:
       return ConsumePrefixedBackgroundBox(range, AllowTextValue::kAllow);
     case CSSPropertyID::kWebkitMaskOrigin:
@@ -895,17 +3011,15 @@
           ConsumeRepeatStyleComponent(range, value, value_y, implicit);
         } else if (property.IDEquals(CSSPropertyID::kBackgroundPositionX) ||
                    property.IDEquals(CSSPropertyID::kWebkitMaskPositionX)) {
-          if (!css_property_parser_helpers::ConsumePosition(
-                  range, context,
-                  css_property_parser_helpers::UnitlessQuirk::kForbid,
-                  WebFeature::kThreeValuedPositionBackground, value, value_y))
+          if (!ConsumePosition(range, context, UnitlessQuirk::kForbid,
+                               WebFeature::kThreeValuedPositionBackground,
+                               value, value_y))
             continue;
           if (value)
             bg_position_parsed_in_current_layer = true;
         } else if (property.IDEquals(CSSPropertyID::kBackgroundSize) ||
                    property.IDEquals(CSSPropertyID::kWebkitMaskSize)) {
-          if (!css_property_parser_helpers::ConsumeSlashIncludingWhitespace(
-                  range))
+          if (!ConsumeSlashIncludingWhitespace(range))
             continue;
           value = ConsumeBackgroundSize(
               range, context,
@@ -961,7 +3075,7 @@
         AddBackgroundValue(longhands[i], CSSInitialValue::Create());
       }
     }
-  } while (css_property_parser_helpers::ConsumeCommaIncludingWhitespace(range));
+  } while (ConsumeCommaIncludingWhitespace(range));
   if (!range.AtEnd())
     return false;
 
@@ -970,12 +3084,10 @@
     if (property.IDEquals(CSSPropertyID::kBackgroundSize) && longhands[i] &&
         context.UseLegacyBackgroundSizeShorthandBehavior())
       continue;
-    css_property_parser_helpers::AddProperty(
-        property.PropertyID(), shorthand.id(), *longhands[i], important,
-        implicit
-            ? css_property_parser_helpers::IsImplicitProperty::kImplicit
-            : css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
+    AddProperty(property.PropertyID(), shorthand.id(), *longhands[i], important,
+                implicit ? IsImplicitProperty::kImplicit
+                         : IsImplicitProperty::kNotImplicit,
+                properties);
   }
   return true;
 }
@@ -984,27 +3096,25 @@
                                  CSSValue*& value1,
                                  CSSValue*& value2,
                                  bool& implicit) {
-  if (css_property_parser_helpers::ConsumeIdent<CSSValueID::kRepeatX>(range)) {
+  if (ConsumeIdent<CSSValueID::kRepeatX>(range)) {
     value1 = CSSIdentifierValue::Create(CSSValueID::kRepeat);
     value2 = CSSIdentifierValue::Create(CSSValueID::kNoRepeat);
     implicit = true;
     return true;
   }
-  if (css_property_parser_helpers::ConsumeIdent<CSSValueID::kRepeatY>(range)) {
+  if (ConsumeIdent<CSSValueID::kRepeatY>(range)) {
     value1 = CSSIdentifierValue::Create(CSSValueID::kNoRepeat);
     value2 = CSSIdentifierValue::Create(CSSValueID::kRepeat);
     implicit = true;
     return true;
   }
-  value1 = css_property_parser_helpers::ConsumeIdent<
-      CSSValueID::kRepeat, CSSValueID::kNoRepeat, CSSValueID::kRound,
-      CSSValueID::kSpace>(range);
+  value1 = ConsumeIdent<CSSValueID::kRepeat, CSSValueID::kNoRepeat,
+                        CSSValueID::kRound, CSSValueID::kSpace>(range);
   if (!value1)
     return false;
 
-  value2 = css_property_parser_helpers::ConsumeIdent<
-      CSSValueID::kRepeat, CSSValueID::kNoRepeat, CSSValueID::kRound,
-      CSSValueID::kSpace>(range);
+  value2 = ConsumeIdent<CSSValueID::kRepeat, CSSValueID::kNoRepeat,
+                        CSSValueID::kRound, CSSValueID::kSpace>(range);
   if (!value2) {
     value2 = value1;
     implicit = true;
@@ -1023,7 +3133,7 @@
       return false;
     AddBackgroundValue(result_x, repeat_x);
     AddBackgroundValue(result_y, repeat_y);
-  } while (css_property_parser_helpers::ConsumeCommaIncludingWhitespace(range));
+  } while (ConsumeCommaIncludingWhitespace(range));
   return true;
 }
 
@@ -1050,7 +3160,7 @@
                                   DefaultFill default_fill) {
   do {
     if (!source) {
-      source = css_property_parser_helpers::ConsumeImageOrNone(range, context);
+      source = ConsumeImageOrNone(range, context);
       if (source)
         continue;
     }
@@ -1064,11 +3174,9 @@
       if (slice) {
         DCHECK(!width);
         DCHECK(!outset);
-        if (css_property_parser_helpers::ConsumeSlashIncludingWhitespace(
-                range)) {
+        if (ConsumeSlashIncludingWhitespace(range)) {
           width = ConsumeBorderImageWidth(range, context);
-          if (css_property_parser_helpers::ConsumeSlashIncludingWhitespace(
-                  range)) {
+          if (ConsumeSlashIncludingWhitespace(range)) {
             outset = ConsumeBorderImageOutset(range, context);
             if (!outset)
               return false;
@@ -1100,16 +3208,14 @@
 CSSValue* ConsumeBorderImageSlice(CSSParserTokenRange& range,
                                   const CSSParserContext& context,
                                   DefaultFill default_fill) {
-  bool fill =
-      css_property_parser_helpers::ConsumeIdent<CSSValueID::kFill>(range);
+  bool fill = ConsumeIdent<CSSValueID::kFill>(range);
   CSSValue* slices[4] = {nullptr};
 
   for (size_t index = 0; index < 4; ++index) {
-    CSSPrimitiveValue* value = css_property_parser_helpers::ConsumePercent(
-        range, context, kValueRangeNonNegative);
+    CSSPrimitiveValue* value =
+        ConsumePercent(range, context, kValueRangeNonNegative);
     if (!value) {
-      value = css_property_parser_helpers::ConsumeNumber(
-          range, context, kValueRangeNonNegative);
+      value = ConsumeNumber(range, context, kValueRangeNonNegative);
     }
     if (!value)
       break;
@@ -1117,12 +3223,12 @@
   }
   if (!slices[0])
     return nullptr;
-  if (css_property_parser_helpers::ConsumeIdent<CSSValueID::kFill>(range)) {
+  if (ConsumeIdent<CSSValueID::kFill>(range)) {
     if (fill)
       return nullptr;
     fill = true;
   }
-  css_property_parser_helpers::Complete4Sides(slices);
+  Complete4Sides(slices);
   if (default_fill == DefaultFill::kFill)
     fill = true;
   return MakeGarbageCollected<cssvalue::CSSBorderImageSliceValue>(
@@ -1138,18 +3244,15 @@
 
   CSSValue* value = nullptr;
   for (size_t index = 0; index < 4; ++index) {
-    value = css_property_parser_helpers::ConsumeNumber(range, context,
-                                                       kValueRangeNonNegative);
+    value = ConsumeNumber(range, context, kValueRangeNonNegative);
     if (!value) {
       CSSParserContext::ParserModeOverridingScope scope(context,
                                                         kHTMLStandardMode);
-      value = css_property_parser_helpers::ConsumeLengthOrPercent(
-          range, context, kValueRangeNonNegative,
-          css_property_parser_helpers::UnitlessQuirk::kForbid);
+      value = ConsumeLengthOrPercent(range, context, kValueRangeNonNegative,
+                                     UnitlessQuirk::kForbid);
     }
     if (!value) {
-      value =
-          css_property_parser_helpers::ConsumeIdent<CSSValueID::kAuto>(range);
+      value = ConsumeIdent<CSSValueID::kAuto>(range);
     }
     if (!value)
       break;
@@ -1157,7 +3260,7 @@
   }
   if (!widths[0])
     return nullptr;
-  css_property_parser_helpers::Complete4Sides(widths);
+  Complete4Sides(widths);
   return MakeGarbageCollected<CSSQuadValue>(widths[0], widths[1], widths[2],
                                             widths[3],
                                             CSSQuadValue::kSerializeAsQuad);
@@ -1169,13 +3272,11 @@
 
   CSSValue* value = nullptr;
   for (size_t index = 0; index < 4; ++index) {
-    value = css_property_parser_helpers::ConsumeNumber(range, context,
-                                                       kValueRangeNonNegative);
+    value = ConsumeNumber(range, context, kValueRangeNonNegative);
     if (!value) {
       CSSParserContext::ParserModeOverridingScope scope(context,
                                                         kHTMLStandardMode);
-      value = css_property_parser_helpers::ConsumeLength(
-          range, context, kValueRangeNonNegative);
+      value = ConsumeLength(range, context, kValueRangeNonNegative);
     }
     if (!value)
       break;
@@ -1183,7 +3284,7 @@
   }
   if (!outsets[0])
     return nullptr;
-  css_property_parser_helpers::Complete4Sides(outsets);
+  Complete4Sides(outsets);
   return MakeGarbageCollected<CSSQuadValue>(outsets[0], outsets[1], outsets[2],
                                             outsets[3],
                                             CSSQuadValue::kSerializeAsQuad);
@@ -1191,12 +3292,12 @@
 
 CSSValue* ParseBorderRadiusCorner(CSSParserTokenRange& range,
                                   const CSSParserContext& context) {
-  CSSValue* parsed_value1 = css_property_parser_helpers::ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative);
+  CSSValue* parsed_value1 =
+      ConsumeLengthOrPercent(range, context, kValueRangeNonNegative);
   if (!parsed_value1)
     return nullptr;
-  CSSValue* parsed_value2 = css_property_parser_helpers::ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative);
+  CSSValue* parsed_value2 =
+      ConsumeLengthOrPercent(range, context, kValueRangeNonNegative);
   if (!parsed_value2)
     parsed_value2 = parsed_value1;
   return MakeGarbageCollected<CSSValuePair>(parsed_value1, parsed_value2,
@@ -1210,10 +3311,8 @@
   bool allow_quirky_lengths = IsQuirksModeBehavior(context.Mode()) &&
                               (shorthand == CSSPropertyID::kInvalid ||
                                shorthand == CSSPropertyID::kBorderWidth);
-  css_property_parser_helpers::UnitlessQuirk unitless =
-      allow_quirky_lengths
-          ? css_property_parser_helpers::UnitlessQuirk::kAllow
-          : css_property_parser_helpers::UnitlessQuirk::kForbid;
+  UnitlessQuirk unitless =
+      allow_quirky_lengths ? UnitlessQuirk::kAllow : UnitlessQuirk::kForbid;
   return ConsumeBorderWidth(range, context, unitless);
 }
 
@@ -1221,9 +3320,9 @@
                         const CSSParserContext& context,
                         AllowInsetAndSpread inset_and_spread) {
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
-      ParseSingleShadow, range, context, inset_and_spread);
+    return ConsumeIdent(range);
+  return ConsumeCommaSeparatedList(ParseSingleShadow, range, context,
+                                   inset_and_spread);
 }
 
 CSSShadowValue* ParseSingleShadow(CSSParserTokenRange& range,
@@ -1235,46 +3334,43 @@
   if (range.AtEnd())
     return nullptr;
 
-  color = css_property_parser_helpers::ConsumeColor(range, context);
+  color = ConsumeColor(range, context);
   if (range.Peek().Id() == CSSValueID::kInset) {
     if (inset_and_spread != AllowInsetAndSpread::kAllow)
       return nullptr;
-    style = css_property_parser_helpers::ConsumeIdent(range);
+    style = ConsumeIdent(range);
     if (!color)
-      color = css_property_parser_helpers::ConsumeColor(range, context);
+      color = ConsumeColor(range, context);
   }
 
   CSSPrimitiveValue* horizontal_offset =
-      css_property_parser_helpers::ConsumeLength(range, context,
-                                                 kValueRangeAll);
+      ConsumeLength(range, context, kValueRangeAll);
   if (!horizontal_offset)
     return nullptr;
 
   CSSPrimitiveValue* vertical_offset =
-      css_property_parser_helpers::ConsumeLength(range, context,
-                                                 kValueRangeAll);
+      ConsumeLength(range, context, kValueRangeAll);
   if (!vertical_offset)
     return nullptr;
 
-  CSSPrimitiveValue* blur_radius = css_property_parser_helpers::ConsumeLength(
-      range, context, kValueRangeNonNegative);
+  CSSPrimitiveValue* blur_radius =
+      ConsumeLength(range, context, kValueRangeNonNegative);
   CSSPrimitiveValue* spread_distance = nullptr;
   if (blur_radius) {
     if (inset_and_spread == AllowInsetAndSpread::kAllow) {
-      spread_distance = css_property_parser_helpers::ConsumeLength(
-          range, context, kValueRangeAll);
+      spread_distance = ConsumeLength(range, context, kValueRangeAll);
     }
   }
 
   if (!range.AtEnd()) {
     if (!color)
-      color = css_property_parser_helpers::ConsumeColor(range, context);
+      color = ConsumeColor(range, context);
     if (range.Peek().Id() == CSSValueID::kInset) {
       if (inset_and_spread != AllowInsetAndSpread::kAllow || style)
         return nullptr;
-      style = css_property_parser_helpers::ConsumeIdent(range);
+      style = ConsumeIdent(range);
       if (!color) {
-        color = css_property_parser_helpers::ConsumeColor(range, context);
+        color = ConsumeColor(range, context);
       }
     }
   }
@@ -1286,19 +3382,19 @@
 CSSValue* ConsumeColumnCount(CSSParserTokenRange& range,
                              const CSSParserContext& context) {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumePositiveInteger(range, context);
+    return ConsumeIdent(range);
+  return ConsumePositiveInteger(range, context);
 }
 
 CSSValue* ConsumeColumnWidth(CSSParserTokenRange& range,
                              const CSSParserContext& context) {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
   // Always parse lengths in strict mode here, since it would be ambiguous
   // otherwise when used in the 'columns' shorthand property.
   CSSParserContext::ParserModeOverridingScope scope(context, kHTMLStandardMode);
-  CSSPrimitiveValue* column_width = css_property_parser_helpers::ConsumeLength(
-      range, context, kValueRangeNonNegative);
+  CSSPrimitiveValue* column_width =
+      ConsumeLength(range, context, kValueRangeNonNegative);
   if (!column_width)
     return nullptr;
   return column_width;
@@ -1309,7 +3405,7 @@
                                CSSValue*& column_width,
                                CSSValue*& column_count) {
   if (range.Peek().Id() == CSSValueID::kAuto) {
-    css_property_parser_helpers::ConsumeIdent(range);
+    ConsumeIdent(range);
     return true;
   }
   if (!column_width) {
@@ -1325,26 +3421,23 @@
 CSSValue* ConsumeGapLength(CSSParserTokenRange& range,
                            const CSSParserContext& context) {
   if (range.Peek().Id() == CSSValueID::kNormal)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative);
+    return ConsumeIdent(range);
+  return ConsumeLengthOrPercent(range, context, kValueRangeNonNegative);
 }
 
 CSSValue* ConsumeCounter(CSSParserTokenRange& range,
                          const CSSParserContext& context,
                          int default_value) {
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
 
   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
   do {
-    CSSCustomIdentValue* counter_name =
-        css_property_parser_helpers::ConsumeCustomIdent(range, context);
+    CSSCustomIdentValue* counter_name = ConsumeCustomIdent(range, context);
     if (!counter_name)
       return nullptr;
     int value = default_value;
-    if (CSSPrimitiveValue* counter_value =
-            css_property_parser_helpers::ConsumeInteger(range, context))
+    if (CSSPrimitiveValue* counter_value = ConsumeInteger(range, context))
       value = clampTo<int>(counter_value->GetDoubleValue());
     list->Append(*MakeGarbageCollected<CSSValuePair>(
         counter_name,
@@ -1359,22 +3452,18 @@
                              const CSSParserContext& context) {
   CSSValueID function_id = range.Peek().FunctionId();
   DCHECK(function_id == CSSValueID::kScriptlevel);
-  CSSParserTokenRange args =
-      css_property_parser_helpers::ConsumeFunction(range);
+  CSSParserTokenRange args = ConsumeFunction(range);
   if (args.AtEnd())
     return nullptr;
-  CSSValue* parsed_value =
-      css_property_parser_helpers::ConsumeIdent<CSSValueID::kAuto>(args);
+  CSSValue* parsed_value = ConsumeIdent<CSSValueID::kAuto>(args);
   if (!parsed_value)
-    parsed_value = css_property_parser_helpers::ConsumeInteger(args, context);
+    parsed_value = ConsumeInteger(args, context);
   if (!parsed_value) {
     function_id = args.Peek().FunctionId();
     if (function_id == CSSValueID::kAdd) {
       auto* add_value = MakeGarbageCollected<CSSFunctionValue>(function_id);
-      CSSParserTokenRange add_args =
-          css_property_parser_helpers::ConsumeFunction(args);
-      if ((parsed_value = css_property_parser_helpers::ConsumeInteger(
-               add_args, context))) {
+      CSSParserTokenRange add_args = ConsumeFunction(args);
+      if ((parsed_value = ConsumeInteger(add_args, context))) {
         add_value->Append(*parsed_value);
         parsed_value = add_value;
       }
@@ -1390,30 +3479,29 @@
 
 CSSValue* ConsumeFontSize(CSSParserTokenRange& range,
                           const CSSParserContext& context,
-                          css_property_parser_helpers::UnitlessQuirk unitless) {
+                          UnitlessQuirk unitless) {
   if (range.Peek().Id() == CSSValueID::kWebkitXxxLarge)
     context.Count(WebFeature::kFontSizeWebkitXxxLarge);
   if (range.Peek().Id() >= CSSValueID::kXxSmall &&
       range.Peek().Id() <= CSSValueID::kWebkitXxxLarge)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
   if (RuntimeEnabledFeatures::CSSMathStyleEnabled() &&
       range.Peek().FunctionId() == CSSValueID::kScriptlevel)
     return ConsumeScriptLevel(range, context);
-  return css_property_parser_helpers::ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative, unitless);
+  return ConsumeLengthOrPercent(range, context, kValueRangeNonNegative,
+                                unitless);
 }
 
 CSSValue* ConsumeLineHeight(CSSParserTokenRange& range,
                             const CSSParserContext& context) {
   if (range.Peek().Id() == CSSValueID::kNormal)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
 
-  CSSPrimitiveValue* line_height = css_property_parser_helpers::ConsumeNumber(
-      range, context, kValueRangeNonNegative);
+  CSSPrimitiveValue* line_height =
+      ConsumeNumber(range, context, kValueRangeNonNegative);
   if (line_height)
     return line_height;
-  return css_property_parser_helpers::ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative);
+  return ConsumeLengthOrPercent(range, context, kValueRangeNonNegative);
 }
 
 CSSValueList* ConsumeFontFamily(CSSParserTokenRange& range) {
@@ -1430,13 +3518,12 @@
         return nullptr;
       }
     }
-  } while (css_property_parser_helpers::ConsumeCommaIncludingWhitespace(range));
+  } while (ConsumeCommaIncludingWhitespace(range));
   return list;
 }
 
 CSSValue* ConsumeGenericFamily(CSSParserTokenRange& range) {
-  return css_property_parser_helpers::ConsumeIdentRange(
-      range, CSSValueID::kSerif, CSSValueID::kWebkitBody);
+  return ConsumeIdentRange(range, CSSValueID::kSerif, CSSValueID::kWebkitBody);
 }
 
 CSSValue* ConsumeFamilyName(CSSParserTokenRange& range) {
@@ -1464,7 +3551,7 @@
     builder.Append(range.ConsumeIncludingWhitespace().Value());
   }
   if (!added_space &&
-      (css_property_parser_helpers::IsCSSWideKeyword(first_token.Value()) ||
+      (IsCSSWideKeyword(first_token.Value()) ||
        EqualIgnoringASCIICase(first_token.Value(), "default"))) {
     return String();
   }
@@ -1494,15 +3581,15 @@
                            const CSSParserContext& context) {
   if (range.Peek().Id() == CSSValueID::kNormal ||
       range.Peek().Id() == CSSValueID::kItalic)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
 
   if (range.Peek().Id() != CSSValueID::kOblique)
     return nullptr;
 
   CSSIdentifierValue* oblique_identifier =
-      css_property_parser_helpers::ConsumeIdent<CSSValueID::kOblique>(range);
+      ConsumeIdent<CSSValueID::kOblique>(range);
 
-  CSSPrimitiveValue* start_angle = css_property_parser_helpers::ConsumeAngle(
+  CSSPrimitiveValue* start_angle = ConsumeAngle(
       range, context, base::nullopt, MinObliqueValue(), MaxObliqueValue());
   if (!start_angle)
     return oblique_identifier;
@@ -1516,7 +3603,7 @@
         *oblique_identifier, *value_list);
   }
 
-  CSSPrimitiveValue* end_angle = css_property_parser_helpers::ConsumeAngle(
+  CSSPrimitiveValue* end_angle = ConsumeAngle(
       range, context, base::nullopt, MinObliqueValue(), MaxObliqueValue());
   if (!end_angle || !IsAngleWithinLimits(end_angle))
     return nullptr;
@@ -1533,7 +3620,7 @@
   if (token.Id() == CSSValueID::kNormal ||
       (token.Id() >= CSSValueID::kUltraCondensed &&
        token.Id() <= CSSValueID::kUltraExpanded))
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
   return nullptr;
 }
 
@@ -1544,8 +3631,7 @@
     return parsed_keyword;
 
   CSSPrimitiveValue* start_percent =
-      css_property_parser_helpers::ConsumePercent(range, context,
-                                                  kValueRangeNonNegative);
+      ConsumePercent(range, context, kValueRangeNonNegative);
   if (!start_percent)
     return nullptr;
 
@@ -1553,8 +3639,8 @@
   if (context.Mode() != kCSSFontFaceRuleMode || range.AtEnd())
     return start_percent;
 
-  CSSPrimitiveValue* end_percent = css_property_parser_helpers::ConsumePercent(
-      range, context, kValueRangeNonNegative);
+  CSSPrimitiveValue* end_percent =
+      ConsumePercent(range, context, kValueRangeNonNegative);
   if (!end_percent)
     return nullptr;
 
@@ -1565,7 +3651,7 @@
                             const CSSParserContext& context) {
   const CSSParserToken& token = range.Peek();
   if (token.Id() >= CSSValueID::kNormal && token.Id() <= CSSValueID::kLighter)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
 
   // Avoid consuming the first zero of font: 0/0; e.g. in the Acid3 test.  In
   // font:0/0; the first zero is the font size, the second is the line height.
@@ -1578,8 +3664,8 @@
       (token.NumericValue() < 1 || token.NumericValue() > 1000))
     return nullptr;
 
-  CSSPrimitiveValue* start_weight = css_property_parser_helpers::ConsumeNumber(
-      range, context, kValueRangeNonNegative);
+  CSSPrimitiveValue* start_weight =
+      ConsumeNumber(range, context, kValueRangeNonNegative);
   if (!start_weight || start_weight->GetFloatValue() < 1 ||
       start_weight->GetFloatValue() > 1000)
     return nullptr;
@@ -1590,8 +3676,8 @@
   if (context.Mode() != kCSSFontFaceRuleMode || range.AtEnd())
     return start_weight;
 
-  CSSPrimitiveValue* end_weight = css_property_parser_helpers::ConsumeNumber(
-      range, context, kValueRangeNonNegative);
+  CSSPrimitiveValue* end_weight =
+      ConsumeNumber(range, context, kValueRangeNonNegative);
   if (!end_weight || end_weight->GetFloatValue() < 1 ||
       end_weight->GetFloatValue() > 1000)
     return nullptr;
@@ -1602,7 +3688,7 @@
 CSSValue* ConsumeFontFeatureSettings(CSSParserTokenRange& range,
                                      const CSSParserContext& context) {
   if (range.Peek().Id() == CSSValueID::kNormal)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
   CSSValueList* settings = CSSValueList::CreateCommaSeparated();
   do {
     CSSFontFeatureValue* font_feature_value =
@@ -1610,7 +3696,7 @@
     if (!font_feature_value)
       return nullptr;
     settings->Append(*font_feature_value);
-  } while (css_property_parser_helpers::ConsumeCommaIncludingWhitespace(range));
+  } while (ConsumeCommaIncludingWhitespace(range));
   return settings;
 }
 
@@ -1636,8 +3722,7 @@
 
   int tag_value = 1;
   // Feature tag values could follow: <integer> | on | off
-  if (CSSPrimitiveValue* value =
-          css_property_parser_helpers::ConsumeInteger(range, context, 0)) {
+  if (CSSPrimitiveValue* value = ConsumeInteger(range, context, 0)) {
     tag_value = clampTo<int>(value->GetDoubleValue());
   } else if (range.Peek().Id() == CSSValueID::kOn ||
              range.Peek().Id() == CSSValueID::kOff) {
@@ -1647,9 +3732,7 @@
 }
 
 CSSIdentifierValue* ConsumeFontVariantCSS21(CSSParserTokenRange& range) {
-  return css_property_parser_helpers::ConsumeIdent<CSSValueID::kNormal,
-                                                   CSSValueID::kSmallCaps>(
-      range);
+  return ConsumeIdent<CSSValueID::kNormal, CSSValueID::kSmallCaps>(range);
 }
 
 Vector<String> ParseGridTemplateAreasColumnNames(const String& grid_row_names) {
@@ -1696,10 +3779,9 @@
 CSSValue* ConsumeGridBreadth(CSSParserTokenRange& range,
                              const CSSParserContext& context) {
   const CSSParserToken& token = range.Peek();
-  if (css_property_parser_helpers::IdentMatches<
-          CSSValueID::kMinContent, CSSValueID::kMaxContent, CSSValueID::kAuto>(
-          token.Id()))
-    return css_property_parser_helpers::ConsumeIdent(range);
+  if (IdentMatches<CSSValueID::kMinContent, CSSValueID::kMaxContent,
+                   CSSValueID::kAuto>(token.Id()))
+    return ConsumeIdent(range);
   if (token.GetType() == kDimensionToken &&
       token.GetUnitType() == CSSPrimitiveValue::UnitType::kFraction) {
     if (range.Peek().NumericValue() < 0)
@@ -1708,20 +3790,16 @@
         range.ConsumeIncludingWhitespace().NumericValue(),
         CSSPrimitiveValue::UnitType::kFraction);
   }
-  return css_property_parser_helpers::ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative,
-      css_property_parser_helpers::UnitlessQuirk::kForbid);
+  return ConsumeLengthOrPercent(range, context, kValueRangeNonNegative,
+                                UnitlessQuirk::kForbid);
 }
 
 CSSValue* ConsumeFitContent(CSSParserTokenRange& range,
                             const CSSParserContext& context) {
   CSSParserTokenRange range_copy = range;
-  CSSParserTokenRange args =
-      css_property_parser_helpers::ConsumeFunction(range_copy);
-  CSSPrimitiveValue* length =
-      css_property_parser_helpers::ConsumeLengthOrPercent(
-          args, context, kValueRangeNonNegative,
-          css_property_parser_helpers::UnitlessQuirk::kAllow);
+  CSSParserTokenRange args = ConsumeFunction(range_copy);
+  CSSPrimitiveValue* length = ConsumeLengthOrPercent(
+      args, context, kValueRangeNonNegative, UnitlessQuirk::kAllow);
   if (!length || !args.AtEnd())
     return nullptr;
   range = range_copy;
@@ -1763,20 +3841,19 @@
 CSSValue* ConsumeGridTrackSize(CSSParserTokenRange& range,
                                const CSSParserContext& context) {
   const CSSParserToken& token = range.Peek();
-  if (css_property_parser_helpers::IdentMatches<CSSValueID::kAuto>(token.Id()))
-    return css_property_parser_helpers::ConsumeIdent(range);
+  if (IdentMatches<CSSValueID::kAuto>(token.Id()))
+    return ConsumeIdent(range);
 
   if (token.FunctionId() == CSSValueID::kMinmax) {
     CSSParserTokenRange range_copy = range;
-    CSSParserTokenRange args =
-        css_property_parser_helpers::ConsumeFunction(range_copy);
+    CSSParserTokenRange args = ConsumeFunction(range_copy);
     CSSValue* min_track_breadth = ConsumeGridBreadth(args, context);
     auto* min_track_breadth_primitive_value =
         DynamicTo<CSSPrimitiveValue>(min_track_breadth);
     if (!min_track_breadth ||
         (min_track_breadth_primitive_value &&
          min_track_breadth_primitive_value->IsFlex()) ||
-        !css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args))
+        !ConsumeCommaIncludingWhitespace(args))
       return nullptr;
     CSSValue* max_track_breadth = ConsumeGridBreadth(args, context);
     if (!max_track_breadth || !args.AtEnd())
@@ -1801,7 +3878,7 @@
       range.Peek().Id() == CSSValueID::kSpan ||
       range.Peek().Id() == CSSValueID::kDefault)
     return nullptr;
-  return css_property_parser_helpers::ConsumeCustomIdent(range, context);
+  return ConsumeCustomIdent(range, context);
 }
 
 // Appends to the passed in CSSGridLineNamesValue if any, otherwise creates a
@@ -1831,28 +3908,26 @@
                                     CSSValueList& list,
                                     bool& is_auto_repeat,
                                     bool& all_tracks_are_fixed_sized) {
-  CSSParserTokenRange args =
-      css_property_parser_helpers::ConsumeFunction(range);
+  CSSParserTokenRange args = ConsumeFunction(range);
   // The number of repetitions for <auto-repeat> is not important at parsing
   // level because it will be computed later, let's set it to 1.
   size_t repetitions = 1;
-  is_auto_repeat = css_property_parser_helpers::IdentMatches<
-      CSSValueID::kAutoFill, CSSValueID::kAutoFit>(args.Peek().Id());
+  is_auto_repeat = IdentMatches<CSSValueID::kAutoFill, CSSValueID::kAutoFit>(
+      args.Peek().Id());
   CSSValueList* repeated_values;
   if (is_auto_repeat) {
     repeated_values = MakeGarbageCollected<cssvalue::CSSGridAutoRepeatValue>(
         args.ConsumeIncludingWhitespace().Id());
   } else {
     // TODO(rob.buis): a consumeIntegerRaw would be more efficient here.
-    CSSPrimitiveValue* repetition =
-        css_property_parser_helpers::ConsumePositiveInteger(args, context);
+    CSSPrimitiveValue* repetition = ConsumePositiveInteger(args, context);
     if (!repetition)
       return false;
     repetitions =
         clampTo<size_t>(repetition->GetDoubleValue(), 0, kGridMaxTracks);
     repeated_values = CSSValueList::CreateSpaceSeparated();
   }
-  if (!css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args))
+  if (!ConsumeCommaIncludingWhitespace(args))
     return false;
   CSSGridLineNamesValue* line_names = ConsumeGridLineNames(args, context);
   if (line_names)
@@ -1940,7 +4015,7 @@
                                range.Peek().Delimiter() == '/'));
 
   if (!range.AtEnd()) {
-    if (!css_property_parser_helpers::ConsumeSlashIncludingWhitespace(range))
+    if (!ConsumeSlashIncludingWhitespace(range))
       return false;
     template_columns = ConsumeGridTrackList(
         range, context, TrackListType::kGridTemplateNoRepeat);
@@ -1959,34 +4034,27 @@
 CSSValue* ConsumeGridLine(CSSParserTokenRange& range,
                           const CSSParserContext& context) {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
 
   CSSIdentifierValue* span_value = nullptr;
   CSSCustomIdentValue* grid_line_name = nullptr;
-  CSSPrimitiveValue* numeric_value =
-      css_property_parser_helpers::ConsumeInteger(range, context);
+  CSSPrimitiveValue* numeric_value = ConsumeInteger(range, context);
   if (numeric_value) {
     grid_line_name = ConsumeCustomIdentForGridLine(range, context);
-    span_value =
-        css_property_parser_helpers::ConsumeIdent<CSSValueID::kSpan>(range);
+    span_value = ConsumeIdent<CSSValueID::kSpan>(range);
   } else {
-    span_value =
-        css_property_parser_helpers::ConsumeIdent<CSSValueID::kSpan>(range);
+    span_value = ConsumeIdent<CSSValueID::kSpan>(range);
     if (span_value) {
-      numeric_value =
-          css_property_parser_helpers::ConsumeInteger(range, context);
+      numeric_value = ConsumeInteger(range, context);
       grid_line_name = ConsumeCustomIdentForGridLine(range, context);
       if (!numeric_value) {
-        numeric_value =
-            css_property_parser_helpers::ConsumeInteger(range, context);
+        numeric_value = ConsumeInteger(range, context);
       }
     } else {
       grid_line_name = ConsumeCustomIdentForGridLine(range, context);
       if (grid_line_name) {
-        numeric_value =
-            css_property_parser_helpers::ConsumeInteger(range, context);
-        span_value =
-            css_property_parser_helpers::ConsumeIdent<CSSValueID::kSpan>(range);
+        numeric_value = ConsumeInteger(range, context);
+        span_value = ConsumeIdent<CSSValueID::kSpan>(range);
         if (!span_value && !numeric_value)
           return grid_line_name;
       } else {
@@ -2135,7 +4203,7 @@
 CSSValue* ConsumeGridTemplatesRowsOrColumns(CSSParserTokenRange& range,
                                             const CSSParserContext& context) {
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
   return ConsumeGridTrackList(range, context, TrackListType::kGridTemplate);
 }
 
@@ -2152,7 +4220,7 @@
   if (!start_value)
     return false;
 
-  if (css_property_parser_helpers::ConsumeSlashIncludingWhitespace(range)) {
+  if (ConsumeSlashIncludingWhitespace(range)) {
     end_value = ConsumeGridLine(range, context);
     if (!end_value)
       return false;
@@ -2178,8 +4246,7 @@
   DCHECK_EQ(gridTemplateShorthand().length(), 3u);
 
   CSSParserTokenRange range_copy = range;
-  template_rows =
-      css_property_parser_helpers::ConsumeIdent<CSSValueID::kNone>(range);
+  template_rows = ConsumeIdent<CSSValueID::kNone>(range);
 
   // 1- 'none' case.
   if (template_rows && range.AtEnd()) {
@@ -2196,7 +4263,7 @@
   }
 
   if (template_rows) {
-    if (!css_property_parser_helpers::ConsumeSlashIncludingWhitespace(range))
+    if (!ConsumeSlashIncludingWhitespace(range))
       return false;
     template_columns = ConsumeGridTemplatesRowsOrColumns(range, context);
     if (!template_columns || !range.AtEnd())
@@ -2282,8 +4349,7 @@
     return nullptr;
 
   CSSParserTokenRange function_range = range;
-  CSSParserTokenRange function_args =
-      css_property_parser_helpers::ConsumeFunction(function_range);
+  CSSParserTokenRange function_args = ConsumeFunction(function_range);
 
   if (function_args.Peek().GetType() != kStringToken)
     return nullptr;
@@ -2306,30 +4372,28 @@
                      const CSSParserContext& context) {
   DCHECK_EQ(range.Peek().FunctionId(), CSSValueID::kRay);
   CSSParserTokenRange function_range = range;
-  CSSParserTokenRange function_args =
-      css_property_parser_helpers::ConsumeFunction(function_range);
+  CSSParserTokenRange function_args = ConsumeFunction(function_range);
 
   CSSPrimitiveValue* angle = nullptr;
   CSSIdentifierValue* size = nullptr;
   CSSIdentifierValue* contain = nullptr;
   while (!function_args.AtEnd()) {
     if (!angle) {
-      angle = css_property_parser_helpers::ConsumeAngle(
-          function_args, context, base::Optional<WebFeature>());
+      angle =
+          ConsumeAngle(function_args, context, base::Optional<WebFeature>());
       if (angle)
         continue;
     }
     if (!size) {
-      size = css_property_parser_helpers::ConsumeIdent<
-          CSSValueID::kClosestSide, CSSValueID::kClosestCorner,
-          CSSValueID::kFarthestSide, CSSValueID::kFarthestCorner,
-          CSSValueID::kSides>(function_args);
+      size =
+          ConsumeIdent<CSSValueID::kClosestSide, CSSValueID::kClosestCorner,
+                       CSSValueID::kFarthestSide, CSSValueID::kFarthestCorner,
+                       CSSValueID::kSides>(function_args);
       if (size)
         continue;
     }
     if (RuntimeEnabledFeatures::CSSOffsetPathRayContainEnabled() && !contain) {
-      contain = css_property_parser_helpers::ConsumeIdent<CSSValueID::kContain>(
-          function_args);
+      contain = ConsumeIdent<CSSValueID::kContain>(function_args);
       if (contain)
         continue;
     }
@@ -2341,46 +4405,41 @@
   return MakeGarbageCollected<cssvalue::CSSRayValue>(*angle, *size, contain);
 }
 
-CSSValue* ConsumeMaxWidthOrHeight(
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    css_property_parser_helpers::UnitlessQuirk unitless) {
+CSSValue* ConsumeMaxWidthOrHeight(CSSParserTokenRange& range,
+                                  const CSSParserContext& context,
+                                  UnitlessQuirk unitless) {
   if (range.Peek().Id() == CSSValueID::kNone ||
       ValidWidthOrHeightKeyword(range.Peek().Id(), context))
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative, unitless);
+    return ConsumeIdent(range);
+  return ConsumeLengthOrPercent(range, context, kValueRangeNonNegative,
+                                unitless);
 }
 
-CSSValue* ConsumeWidthOrHeight(
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    css_property_parser_helpers::UnitlessQuirk unitless) {
+CSSValue* ConsumeWidthOrHeight(CSSParserTokenRange& range,
+                               const CSSParserContext& context,
+                               UnitlessQuirk unitless) {
   if (range.Peek().Id() == CSSValueID::kAuto ||
       ValidWidthOrHeightKeyword(range.Peek().Id(), context))
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative, unitless);
+    return ConsumeIdent(range);
+  return ConsumeLengthOrPercent(range, context, kValueRangeNonNegative,
+                                unitless);
 }
 
-CSSValue* ConsumeMarginOrOffset(
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    css_property_parser_helpers::UnitlessQuirk unitless) {
+CSSValue* ConsumeMarginOrOffset(CSSParserTokenRange& range,
+                                const CSSParserContext& context,
+                                UnitlessQuirk unitless) {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeLengthOrPercent(
-      range, context, kValueRangeAll, unitless);
+    return ConsumeIdent(range);
+  return ConsumeLengthOrPercent(range, context, kValueRangeAll, unitless);
 }
 
 CSSValue* ConsumeScrollPadding(CSSParserTokenRange& range,
                                const CSSParserContext& context) {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
   CSSParserContext::ParserModeOverridingScope scope(context, kHTMLStandardMode);
-  return css_property_parser_helpers::ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative,
-      css_property_parser_helpers::UnitlessQuirk::kForbid);
+  return ConsumeLengthOrPercent(range, context, kValueRangeNonNegative,
+                                UnitlessQuirk::kForbid);
 }
 
 CSSValue* ConsumeOffsetPath(CSSParserTokenRange& range,
@@ -2401,24 +4460,21 @@
 CSSValue* ConsumePathOrNone(CSSParserTokenRange& range) {
   CSSValueID id = range.Peek().Id();
   if (id == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
 
   return ConsumePath(range);
 }
 
 CSSValue* ConsumeOffsetRotate(CSSParserTokenRange& range,
                               const CSSParserContext& context) {
-  CSSValue* angle = css_property_parser_helpers::ConsumeAngle(
-      range, context, base::Optional<WebFeature>());
+  CSSValue* angle = ConsumeAngle(range, context, base::Optional<WebFeature>());
   CSSValue* keyword =
-      css_property_parser_helpers::ConsumeIdent<CSSValueID::kAuto,
-                                                CSSValueID::kReverse>(range);
+      ConsumeIdent<CSSValueID::kAuto, CSSValueID::kReverse>(range);
   if (!angle && !keyword)
     return nullptr;
 
   if (!angle) {
-    angle = css_property_parser_helpers::ConsumeAngle(
-        range, context, base::Optional<WebFeature>());
+    angle = ConsumeAngle(range, context, base::Optional<WebFeature>());
   }
 
   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
@@ -2439,8 +4495,7 @@
          range.Peek().GetType() != kDelimiterToken;
        ++horizontal_value_count) {
     horizontal_radii[horizontal_value_count] =
-        css_property_parser_helpers::ConsumeLengthOrPercent(
-            range, context, kValueRangeNonNegative);
+        ConsumeLengthOrPercent(range, context, kValueRangeNonNegative);
     if (!horizontal_radii[horizontal_value_count])
       return false;
   }
@@ -2453,25 +4508,25 @@
       vertical_radii[0] = horizontal_radii[1];
       horizontal_radii[1] = nullptr;
     } else {
-      css_property_parser_helpers::Complete4Sides(horizontal_radii);
+      Complete4Sides(horizontal_radii);
       for (unsigned i = 0; i < 4; ++i)
         vertical_radii[i] = horizontal_radii[i];
       return true;
     }
   } else {
-    if (!css_property_parser_helpers::ConsumeSlashIncludingWhitespace(range))
+    if (!ConsumeSlashIncludingWhitespace(range))
       return false;
     for (unsigned i = 0; i < 4 && !range.AtEnd(); ++i) {
-      vertical_radii[i] = css_property_parser_helpers::ConsumeLengthOrPercent(
-          range, context, kValueRangeNonNegative);
+      vertical_radii[i] =
+          ConsumeLengthOrPercent(range, context, kValueRangeNonNegative);
       if (!vertical_radii[i])
         return false;
     }
     if (!vertical_radii[0] || !range.AtEnd())
       return false;
   }
-  css_property_parser_helpers::Complete4Sides(horizontal_radii);
-  css_property_parser_helpers::Complete4Sides(vertical_radii);
+  Complete4Sides(horizontal_radii);
+  Complete4Sides(vertical_radii);
   return true;
 }
 
@@ -2482,8 +4537,7 @@
     return nullptr;
   CSSValueID id = range.Peek().FunctionId();
   CSSParserTokenRange range_copy = range;
-  CSSParserTokenRange args =
-      css_property_parser_helpers::ConsumeFunction(range_copy);
+  CSSParserTokenRange args = ConsumeFunction(range_copy);
   if (id == CSSValueID::kCircle)
     shape = ConsumeBasicShapeCircle(args, context);
   else if (id == CSSValueID::kEllipse)
@@ -2504,7 +4558,7 @@
 CSSValue* ConsumeTextDecorationLine(CSSParserTokenRange& range) {
   CSSValueID id = range.Peek().Id();
   if (id == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
 
   CSSIdentifierValue* underline = nullptr;
   CSSIdentifierValue* overline = nullptr;
@@ -2514,13 +4568,13 @@
   while (true) {
     id = range.Peek().Id();
     if (id == CSSValueID::kUnderline && !underline)
-      underline = css_property_parser_helpers::ConsumeIdent(range);
+      underline = ConsumeIdent(range);
     else if (id == CSSValueID::kOverline && !overline)
-      overline = css_property_parser_helpers::ConsumeIdent(range);
+      overline = ConsumeIdent(range);
     else if (id == CSSValueID::kLineThrough && !line_through)
-      line_through = css_property_parser_helpers::ConsumeIdent(range);
+      line_through = ConsumeIdent(range);
     else if (id == CSSValueID::kBlink && !blink)
-      blink = css_property_parser_helpers::ConsumeIdent(range);
+      blink = ConsumeIdent(range);
     else
       break;
   }
@@ -2546,8 +4600,7 @@
   CSSValueID function_id = range.Peek().FunctionId();
   if (!IsValidCSSValueID(function_id))
     return nullptr;
-  CSSParserTokenRange args =
-      css_property_parser_helpers::ConsumeFunction(range);
+  CSSParserTokenRange args = ConsumeFunction(range);
   if (args.AtEnd())
     return nullptr;
   auto* transform_value = MakeGarbageCollected<CSSFunctionValue>(function_id);
@@ -2560,15 +4613,15 @@
     case CSSValueID::kSkewX:
     case CSSValueID::kSkewY:
     case CSSValueID::kSkew:
-      parsed_value = css_property_parser_helpers::ConsumeAngle(
-          args, context, WebFeature::kUnitlessZeroAngleTransform);
+      parsed_value =
+          ConsumeAngle(args, context, WebFeature::kUnitlessZeroAngleTransform);
       if (!parsed_value)
         return nullptr;
       if (function_id == CSSValueID::kSkew &&
-          css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args)) {
+          ConsumeCommaIncludingWhitespace(args)) {
         transform_value->Append(*parsed_value);
-        parsed_value = css_property_parser_helpers::ConsumeAngle(
-            args, context, WebFeature::kUnitlessZeroAngleTransform);
+        parsed_value = ConsumeAngle(args, context,
+                                    WebFeature::kUnitlessZeroAngleTransform);
         if (!parsed_value)
           return nullptr;
       }
@@ -2577,15 +4630,13 @@
     case CSSValueID::kScaleY:
     case CSSValueID::kScaleZ:
     case CSSValueID::kScale:
-      parsed_value = css_property_parser_helpers::ConsumeNumber(args, context,
-                                                                kValueRangeAll);
+      parsed_value = ConsumeNumber(args, context, kValueRangeAll);
       if (!parsed_value)
         return nullptr;
       if (function_id == CSSValueID::kScale &&
-          css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args)) {
+          ConsumeCommaIncludingWhitespace(args)) {
         transform_value->Append(*parsed_value);
-        parsed_value = css_property_parser_helpers::ConsumeNumber(
-            args, context, kValueRangeAll);
+        parsed_value = ConsumeNumber(args, context, kValueRangeAll);
         if (!parsed_value)
           return nullptr;
       }
@@ -2599,22 +4650,19 @@
     case CSSValueID::kTranslateX:
     case CSSValueID::kTranslateY:
     case CSSValueID::kTranslate:
-      parsed_value = css_property_parser_helpers::ConsumeLengthOrPercent(
-          args, context, kValueRangeAll);
+      parsed_value = ConsumeLengthOrPercent(args, context, kValueRangeAll);
       if (!parsed_value)
         return nullptr;
       if (function_id == CSSValueID::kTranslate &&
-          css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args)) {
+          ConsumeCommaIncludingWhitespace(args)) {
         transform_value->Append(*parsed_value);
-        parsed_value = css_property_parser_helpers::ConsumeLengthOrPercent(
-            args, context, kValueRangeAll);
+        parsed_value = ConsumeLengthOrPercent(args, context, kValueRangeAll);
         if (!parsed_value)
           return nullptr;
       }
       break;
     case CSSValueID::kTranslateZ:
-      parsed_value = css_property_parser_helpers::ConsumeLength(args, context,
-                                                                kValueRangeAll);
+      parsed_value = ConsumeLength(args, context, kValueRangeAll);
       break;
     case CSSValueID::kMatrix:
     case CSSValueID::kMatrix3d:
@@ -2629,11 +4677,11 @@
       break;
     case CSSValueID::kRotate3d:
       if (!ConsumeNumbers(args, context, transform_value, 3) ||
-          !css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args)) {
+          !ConsumeCommaIncludingWhitespace(args)) {
         return nullptr;
       }
-      parsed_value = css_property_parser_helpers::ConsumeAngle(
-          args, context, WebFeature::kUnitlessZeroAngleTransform);
+      parsed_value =
+          ConsumeAngle(args, context, WebFeature::kUnitlessZeroAngleTransform);
       if (!parsed_value)
         return nullptr;
       break;
@@ -2655,7 +4703,7 @@
                                const CSSParserContext& context,
                                const CSSParserLocalContext& local_context) {
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
 
   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
   do {
@@ -2675,7 +4723,7 @@
   if (token.GetType() != kIdentToken)
     return nullptr;
   if (token.Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
   const auto* execution_context = context.GetExecutionContext();
   CSSPropertyID unresolved_property =
       token.ParseAsUnresolvedCSSPropertyID(execution_context);
@@ -2688,7 +4736,7 @@
     range.ConsumeIncludingWhitespace();
     return MakeGarbageCollected<CSSCustomIdentValue>(unresolved_property);
   }
-  return css_property_parser_helpers::ConsumeCustomIdent(range, context);
+  return ConsumeCustomIdent(range, context);
 }
 
 bool IsValidPropertyList(const CSSValueList& value_list) {
@@ -2709,40 +4757,34 @@
   bool allow_quirky_colors = IsQuirksModeBehavior(context.Mode()) &&
                              (shorthand == CSSPropertyID::kInvalid ||
                               shorthand == CSSPropertyID::kBorderColor);
-  return css_property_parser_helpers::ConsumeColor(range, context,
-                                                   allow_quirky_colors);
+  return ConsumeColor(range, context, allow_quirky_colors);
 }
 
-CSSValue* ConsumeBorderWidth(
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    css_property_parser_helpers::UnitlessQuirk unitless) {
-  return css_property_parser_helpers::ConsumeLineWidth(range, context,
-                                                       unitless);
+CSSValue* ConsumeBorderWidth(CSSParserTokenRange& range,
+                             const CSSParserContext& context,
+                             UnitlessQuirk unitless) {
+  return ConsumeLineWidth(range, context, unitless);
 }
 
 CSSValue* ParseSpacing(CSSParserTokenRange& range,
                        const CSSParserContext& context) {
   if (range.Peek().Id() == CSSValueID::kNormal)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return ConsumeIdent(range);
   // TODO(timloh): allow <percentage>s in word-spacing.
-  return css_property_parser_helpers::ConsumeLength(
-      range, context, kValueRangeAll,
-      css_property_parser_helpers::UnitlessQuirk::kAllow);
+  return ConsumeLength(range, context, kValueRangeAll, UnitlessQuirk::kAllow);
 }
 
 CSSValue* ParsePaintStroke(CSSParserTokenRange& range,
                            const CSSParserContext& context) {
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  cssvalue::CSSURIValue* url =
-      css_property_parser_helpers::ConsumeUrl(range, context);
+    return ConsumeIdent(range);
+  cssvalue::CSSURIValue* url = ConsumeUrl(range, context);
   if (url) {
     CSSValue* parsed_value = nullptr;
     if (range.Peek().Id() == CSSValueID::kNone) {
-      parsed_value = css_property_parser_helpers::ConsumeIdent(range);
+      parsed_value = ConsumeIdent(range);
     } else {
-      parsed_value = css_property_parser_helpers::ConsumeColor(range, context);
+      parsed_value = ConsumeColor(range, context);
     }
     if (parsed_value) {
       CSSValueList* values = CSSValueList::CreateSpaceSeparated();
@@ -2752,14 +4794,14 @@
     }
     return url;
   }
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return ConsumeColor(range, context);
 }
 
-css_property_parser_helpers::UnitlessQuirk UnitlessUnlessShorthand(
+UnitlessQuirk UnitlessUnlessShorthand(
     const CSSParserLocalContext& local_context) {
   return local_context.CurrentShorthand() == CSSPropertyID::kInvalid
-             ? css_property_parser_helpers::UnitlessQuirk::kAllow
-             : css_property_parser_helpers::UnitlessQuirk::kForbid;
+             ? UnitlessQuirk::kAllow
+             : UnitlessQuirk::kForbid;
 }
 
 }  // namespace css_parsing_utils
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.h b/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
index ce0c483..19323a5 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
@@ -5,27 +5,42 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PROPERTIES_CSS_PARSING_UTILS_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PROPERTIES_CSS_PARSING_UTILS_H_
 
+#include "base/optional.h"
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
+#include "third_party/blink/renderer/core/css/css_function_value.h"
+#include "third_party/blink/renderer/core/css/css_identifier_value.h"
 #include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
+#include "third_party/blink/renderer/core/css/css_primitive_value.h"
+#include "third_party/blink/renderer/core/css/css_value_list.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_mode.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
-#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
 #include "third_party/blink/renderer/core/css_value_keywords.h"
+#include "third_party/blink/renderer/core/frame/web_feature_forward.h"
 #include "third_party/blink/renderer/core/style/grid_area.h"
+#include "third_party/blink/renderer/platform/geometry/length.h"  // For ValueRange
+#include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
 
 namespace cssvalue {
 class CSSFontFeatureValue;
+class CSSURIValue;
 }  // namespace cssvalue
 class CSSIdentifierValue;
 class CSSParserContext;
 class CSSParserLocalContext;
+class CSSPropertyValue;
 class CSSShadowValue;
+class CSSStringValue;
 class CSSValue;
 class CSSValueList;
+class CSSValuePair;
 class StylePropertyShorthand;
 
+// "Consume" functions, when successful, should consume all the relevant tokens
+// as well as any trailing whitespace. When the start of the range doesn't
+// match the type we're looking for, the range should not be modified.
 namespace css_parsing_utils {
 
 enum class AllowInsetAndSpread { kAllow, kForbid };
@@ -33,6 +48,7 @@
 enum class DefaultFill { kFill, kNoFill };
 enum class ParsingStyle { kLegacy, kNotLegacy };
 enum class TrackListType { kGridTemplate, kGridTemplateNoRepeat, kGridAuto };
+enum class UnitlessQuirk { kAllow, kForbid };
 
 using ConsumeAnimationItemValue = CSSValue* (*)(CSSPropertyID,
                                                 CSSParserTokenRange&,
@@ -42,12 +58,180 @@
 
 constexpr size_t kMaxNumAnimationLonghands = 8;
 
+void Complete4Sides(CSSValue* side[4]);
+
+// TODO(timloh): These should probably just be consumeComma and consumeSlash.
+bool ConsumeCommaIncludingWhitespace(CSSParserTokenRange&);
+bool ConsumeSlashIncludingWhitespace(CSSParserTokenRange&);
+// consumeFunction expects the range starts with a FunctionToken.
+CSSParserTokenRange ConsumeFunction(CSSParserTokenRange&);
+
+CSSPrimitiveValue* ConsumeInteger(
+    CSSParserTokenRange&,
+    const CSSParserContext&,
+    double minimum_value = -std::numeric_limits<double>::max());
+CSSPrimitiveValue* ConsumeIntegerOrNumberCalc(CSSParserTokenRange&,
+                                              const CSSParserContext&);
+CSSPrimitiveValue* ConsumePositiveInteger(CSSParserTokenRange&,
+                                          const CSSParserContext&);
+bool ConsumeNumberRaw(CSSParserTokenRange&,
+                      const CSSParserContext& context,
+                      double& result);
+CSSPrimitiveValue* ConsumeNumber(CSSParserTokenRange&,
+                                 const CSSParserContext&,
+                                 ValueRange);
+CSSPrimitiveValue* ConsumeLength(CSSParserTokenRange&,
+                                 const CSSParserContext&,
+                                 ValueRange,
+                                 UnitlessQuirk = UnitlessQuirk::kForbid);
+CSSPrimitiveValue* ConsumePercent(CSSParserTokenRange&,
+                                  const CSSParserContext&,
+                                  ValueRange);
+CSSPrimitiveValue* ConsumeAlphaValue(CSSParserTokenRange&,
+                                     const CSSParserContext&);
+CSSPrimitiveValue* ConsumeLengthOrPercent(
+    CSSParserTokenRange&,
+    const CSSParserContext&,
+    ValueRange,
+    UnitlessQuirk = UnitlessQuirk::kForbid);
+CSSPrimitiveValue* ConsumeSVGGeometryPropertyLength(CSSParserTokenRange&,
+                                                    const CSSParserContext&,
+                                                    ValueRange);
+
+CSSPrimitiveValue* ConsumeAngle(
+    CSSParserTokenRange&,
+    const CSSParserContext&,
+    base::Optional<WebFeature> unitless_zero_feature);
+CSSPrimitiveValue* ConsumeAngle(
+    CSSParserTokenRange&,
+    const CSSParserContext&,
+    base::Optional<WebFeature> unitless_zero_feature,
+    double minimum_value,
+    double maximum_value);
+CSSPrimitiveValue* ConsumeTime(CSSParserTokenRange&,
+                               const CSSParserContext&,
+                               ValueRange);
+CSSPrimitiveValue* ConsumeResolution(CSSParserTokenRange&);
+
+CSSIdentifierValue* ConsumeIdent(CSSParserTokenRange&);
+CSSIdentifierValue* ConsumeIdentRange(CSSParserTokenRange&,
+                                      CSSValueID lower,
+                                      CSSValueID upper);
+template <CSSValueID, CSSValueID...>
+inline bool IdentMatches(CSSValueID id);
+template <CSSValueID... allowedIdents>
+CSSIdentifierValue* ConsumeIdent(CSSParserTokenRange&);
+
+CSSCustomIdentValue* ConsumeCustomIdent(CSSParserTokenRange&,
+                                        const CSSParserContext&);
+CSSStringValue* ConsumeString(CSSParserTokenRange&);
+StringView ConsumeUrlAsStringView(CSSParserTokenRange&,
+                                  const CSSParserContext&);
+cssvalue::CSSURIValue* ConsumeUrl(CSSParserTokenRange&,
+                                  const CSSParserContext&);
+
+CSSValue* ConsumeColor(CSSParserTokenRange&,
+                       const CSSParserContext&,
+                       bool accept_quirky_colors = false);
+
+CSSValue* ConsumeInternalForcedBackgroundColor(CSSParserTokenRange&,
+                                               const CSSParserContext&);
+
+CSSValue* ConsumeLineWidth(CSSParserTokenRange&,
+                           const CSSParserContext&,
+                           UnitlessQuirk);
+
+CSSValuePair* ConsumePosition(CSSParserTokenRange&,
+                              const CSSParserContext&,
+                              UnitlessQuirk,
+                              base::Optional<WebFeature> three_value_position);
+bool ConsumePosition(CSSParserTokenRange&,
+                     const CSSParserContext&,
+                     UnitlessQuirk,
+                     base::Optional<WebFeature> three_value_position,
+                     CSSValue*& result_x,
+                     CSSValue*& result_y);
+bool ConsumeOneOrTwoValuedPosition(CSSParserTokenRange&,
+                                   const CSSParserContext&,
+                                   UnitlessQuirk,
+                                   CSSValue*& result_x,
+                                   CSSValue*& result_y);
+bool ConsumeBorderShorthand(CSSParserTokenRange&,
+                            const CSSParserContext&,
+                            const CSSValue*& result_width,
+                            const CSSValue*& result_style,
+                            const CSSValue*& result_color);
+
+enum class ConsumeGeneratedImagePolicy { kAllow, kForbid };
+
+CSSValue* ConsumeImage(
+    CSSParserTokenRange&,
+    const CSSParserContext&,
+    ConsumeGeneratedImagePolicy = ConsumeGeneratedImagePolicy::kAllow);
+CSSValue* ConsumeImageOrNone(CSSParserTokenRange&, const CSSParserContext&);
+
+CSSValue* ConsumeAxis(CSSParserTokenRange&, const CSSParserContext& context);
+
+CSSIdentifierValue* ConsumeShapeBox(CSSParserTokenRange&);
+
+enum class IsImplicitProperty { kNotImplicit, kImplicit };
+
+void AddProperty(CSSPropertyID resolved_property,
+                 CSSPropertyID current_shorthand,
+                 const CSSValue&,
+                 bool important,
+                 IsImplicitProperty,
+                 HeapVector<CSSPropertyValue, 256>& properties);
+
+void CountKeywordOnlyPropertyUsage(CSSPropertyID,
+                                   const CSSParserContext&,
+                                   CSSValueID);
+
+const CSSValue* ParseLonghand(CSSPropertyID unresolved_property,
+                              CSSPropertyID current_shorthand,
+                              const CSSParserContext&,
+                              CSSParserTokenRange&);
+
+bool ConsumeShorthandVia2Longhands(
+    const StylePropertyShorthand&,
+    bool important,
+    const CSSParserContext&,
+    CSSParserTokenRange&,
+    HeapVector<CSSPropertyValue, 256>& properties);
+
+bool ConsumeShorthandVia4Longhands(
+    const StylePropertyShorthand&,
+    bool important,
+    const CSSParserContext&,
+    CSSParserTokenRange&,
+    HeapVector<CSSPropertyValue, 256>& properties);
+
+bool ConsumeShorthandGreedilyViaLonghands(
+    const StylePropertyShorthand&,
+    bool important,
+    const CSSParserContext&,
+    CSSParserTokenRange&,
+    HeapVector<CSSPropertyValue, 256>& properties);
+
+void AddExpandedPropertyForValue(CSSPropertyID prop_id,
+                                 const CSSValue&,
+                                 bool,
+                                 HeapVector<CSSPropertyValue, 256>& properties);
+
+CSSValue* ConsumeTransformValue(CSSParserTokenRange&, const CSSParserContext&);
+CSSValue* ConsumeTransformList(CSSParserTokenRange&, const CSSParserContext&);
+CSSValue* ConsumeFilterFunctionList(CSSParserTokenRange&,
+                                    const CSSParserContext&);
+
 bool IsBaselineKeyword(CSSValueID id);
 bool IsSelfPositionKeyword(CSSValueID);
 bool IsSelfPositionOrLeftOrRightKeyword(CSSValueID);
 bool IsContentPositionKeyword(CSSValueID);
 bool IsContentPositionOrLeftOrRightKeyword(CSSValueID);
 CORE_EXPORT bool IsCSSWideKeyword(CSSValueID);
+CORE_EXPORT bool IsCSSWideKeyword(StringView);
+bool IsRevertKeyword(StringView);
+bool IsDefaultKeyword(StringView);
 
 CSSValue* ConsumeScrollOffset(CSSParserTokenRange&, const CSSParserContext&);
 CSSValue* ConsumeSelfPositionOverflowPosition(CSSParserTokenRange&,
@@ -86,7 +270,7 @@
 CSSValue* ConsumeMaskSourceType(CSSParserTokenRange&);
 bool ConsumeBackgroundPosition(CSSParserTokenRange&,
                                const CSSParserContext&,
-                               css_property_parser_helpers::UnitlessQuirk,
+                               UnitlessQuirk,
                                CSSValue*& result_x,
                                CSSValue*& result_y);
 CSSValue* ConsumePrefixedBackgroundBox(CSSParserTokenRange&, AllowTextValue);
@@ -154,11 +338,9 @@
 
 CSSValue* ConsumeCounter(CSSParserTokenRange&, const CSSParserContext&, int);
 
-CSSValue* ConsumeFontSize(
-    CSSParserTokenRange&,
-    const CSSParserContext&,
-    css_property_parser_helpers::UnitlessQuirk =
-        css_property_parser_helpers::UnitlessQuirk::kForbid);
+CSSValue* ConsumeFontSize(CSSParserTokenRange&,
+                          const CSSParserContext&,
+                          UnitlessQuirk = UnitlessQuirk::kForbid);
 
 CSSValue* ConsumeLineHeight(CSSParserTokenRange&, const CSSParserContext&);
 
@@ -206,20 +388,16 @@
 bool ConsumeFromColumnBreakBetween(CSSParserTokenRange&, CSSValueID&);
 bool ConsumeFromColumnOrPageBreakInside(CSSParserTokenRange&, CSSValueID&);
 
-CSSValue* ConsumeMaxWidthOrHeight(
-    CSSParserTokenRange&,
-    const CSSParserContext&,
-    css_property_parser_helpers::UnitlessQuirk =
-        css_property_parser_helpers::UnitlessQuirk::kForbid);
-CSSValue* ConsumeWidthOrHeight(
-    CSSParserTokenRange&,
-    const CSSParserContext&,
-    css_property_parser_helpers::UnitlessQuirk =
-        css_property_parser_helpers::UnitlessQuirk::kForbid);
+CSSValue* ConsumeMaxWidthOrHeight(CSSParserTokenRange&,
+                                  const CSSParserContext&,
+                                  UnitlessQuirk = UnitlessQuirk::kForbid);
+CSSValue* ConsumeWidthOrHeight(CSSParserTokenRange&,
+                               const CSSParserContext&,
+                               UnitlessQuirk = UnitlessQuirk::kForbid);
 
 CSSValue* ConsumeMarginOrOffset(CSSParserTokenRange&,
                                 const CSSParserContext&,
-                                css_property_parser_helpers::UnitlessQuirk);
+                                UnitlessQuirk);
 CSSValue* ConsumeScrollPadding(CSSParserTokenRange&, const CSSParserContext&);
 CSSValue* ConsumeOffsetPath(CSSParserTokenRange&, const CSSParserContext&);
 CSSValue* ConsumePathOrNone(CSSParserTokenRange&);
@@ -249,12 +427,48 @@
                                  const CSSParserLocalContext&);
 CSSValue* ConsumeBorderWidth(CSSParserTokenRange&,
                              const CSSParserContext&,
-                             css_property_parser_helpers::UnitlessQuirk);
+                             UnitlessQuirk);
 CSSValue* ParsePaintStroke(CSSParserTokenRange&, const CSSParserContext&);
 CSSValue* ParseSpacing(CSSParserTokenRange&, const CSSParserContext&);
 
-css_property_parser_helpers::UnitlessQuirk UnitlessUnlessShorthand(
-    const CSSParserLocalContext&);
+UnitlessQuirk UnitlessUnlessShorthand(const CSSParserLocalContext&);
+
+// Template implementations are at the bottom of the file for readability.
+
+template <typename... emptyBaseCase>
+inline bool IdentMatches(CSSValueID id) {
+  return false;
+}
+template <CSSValueID head, CSSValueID... tail>
+inline bool IdentMatches(CSSValueID id) {
+  return id == head || IdentMatches<tail...>(id);
+}
+
+template <CSSValueID... names>
+CSSIdentifierValue* ConsumeIdent(CSSParserTokenRange& range) {
+  if (range.Peek().GetType() != kIdentToken ||
+      !IdentMatches<names...>(range.Peek().Id()))
+    return nullptr;
+  return CSSIdentifierValue::Create(range.ConsumeIncludingWhitespace().Id());
+}
+
+// ConsumeCommaSeparatedList takes a callback function to call on each item in
+// the list, followed by the arguments to pass to this callback.
+// The first argument to the callback must be the CSSParserTokenRange
+template <typename Func, typename... Args>
+CSSValueList* ConsumeCommaSeparatedList(Func callback,
+                                        CSSParserTokenRange& range,
+                                        Args&&... args) {
+  CSSValueList* list = CSSValueList::CreateCommaSeparated();
+  do {
+    CSSValue* value = callback(range, std::forward<Args>(args)...);
+    if (!value)
+      return nullptr;
+    list->Append(*value);
+  } while (ConsumeCommaIncludingWhitespace(range));
+  DCHECK(list->length());
+  return list;
+}
 
 template <CSSValueID start, CSSValueID end>
 CSSValue* ConsumePositionLonghand(CSSParserTokenRange& range,
@@ -274,8 +488,7 @@
     return CSSNumericLiteralValue::Create(
         percent, CSSPrimitiveValue::UnitType::kPercentage);
   }
-  return css_property_parser_helpers::ConsumeLengthOrPercent(range, context,
-                                                             kValueRangeAll);
+  return ConsumeLengthOrPercent(range, context, kValueRangeAll);
 }
 
 }  // namespace css_parsing_utils
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils_test.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils_test.cc
index 3e768f51..9e794bed 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils_test.cc
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils_test.cc
@@ -26,11 +26,13 @@
   {
     ScopedCSSRevertForTest scoped_revert(true);
     EXPECT_TRUE(css_parsing_utils::IsCSSWideKeyword(CSSValueID::kRevert));
+    EXPECT_TRUE(css_parsing_utils::IsCSSWideKeyword("revert"));
   }
 
   {
     ScopedCSSRevertForTest scoped_revert(false);
     EXPECT_FALSE(css_parsing_utils::IsCSSWideKeyword(CSSValueID::kRevert));
+    EXPECT_FALSE(css_parsing_utils::IsCSSWideKeyword("revert"));
   }
 }
 
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
index 9e06f679..0370ab8 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -32,7 +32,6 @@
 #include "third_party/blink/renderer/core/css/parser/css_parser_token.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
 #include "third_party/blink/renderer/core/css/parser/css_property_parser.h"
-#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
 #include "third_party/blink/renderer/core/css/parser/font_variant_east_asian_parser.h"
 #include "third_party/blink/renderer/core/css/parser/font_variant_ligatures_parser.h"
 #include "third_party/blink/renderer/core/css/parser/font_variant_numeric_parser.h"
@@ -86,8 +85,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   // align-items property does not allow the 'auto' value.
-  if (css_property_parser_helpers::IdentMatches<CSSValueID::kAuto>(
-          range.Peek().Id()))
+  if (css_parsing_utils::IdentMatches<CSSValueID::kAuto>(range.Peek().Id()))
     return nullptr;
   return css_parsing_utils::ConsumeSelfPositionOverflowPosition(
       range, css_parsing_utils::IsSelfPositionKeyword);
@@ -130,8 +128,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
-      css_property_parser_helpers::ConsumeTime, range, context, kValueRangeAll);
+  return css_parsing_utils::ConsumeCommaSeparatedList(
+      css_parsing_utils::ConsumeTime, range, context, kValueRangeAll);
 }
 
 const CSSValue* AnimationDelay::CSSValueFromComputedStyleInternal(
@@ -154,8 +152,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext&,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
-      css_property_parser_helpers::ConsumeIdent<
+  return css_parsing_utils::ConsumeCommaSeparatedList(
+      css_parsing_utils::ConsumeIdent<
           CSSValueID::kNormal, CSSValueID::kAlternate, CSSValueID::kReverse,
           CSSValueID::kAlternateReverse>,
       range);
@@ -189,9 +187,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
-      css_property_parser_helpers::ConsumeTime, range, context,
-      kValueRangeNonNegative);
+  return css_parsing_utils::ConsumeCommaSeparatedList(
+      css_parsing_utils::ConsumeTime, range, context, kValueRangeNonNegative);
 }
 
 const CSSValue* AnimationDuration::CSSValueFromComputedStyleInternal(
@@ -214,10 +211,10 @@
     CSSParserTokenRange& range,
     const CSSParserContext&,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
-      css_property_parser_helpers::ConsumeIdent<
-          CSSValueID::kNone, CSSValueID::kForwards, CSSValueID::kBackwards,
-          CSSValueID::kBoth>,
+  return css_parsing_utils::ConsumeCommaSeparatedList(
+      css_parsing_utils::ConsumeIdent<CSSValueID::kNone, CSSValueID::kForwards,
+                                      CSSValueID::kBackwards,
+                                      CSSValueID::kBoth>,
       range);
 }
 
@@ -249,7 +246,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
+  return css_parsing_utils::ConsumeCommaSeparatedList(
       css_parsing_utils::ConsumeAnimationIterationCount, range, context);
 }
 
@@ -285,7 +282,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext& local_context) const {
   // Allow quoted name if this is an alias property.
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
+  return css_parsing_utils::ConsumeCommaSeparatedList(
       css_parsing_utils::ConsumeAnimationName, range, context,
       local_context.UseAliasParsing());
 }
@@ -318,9 +315,9 @@
     CSSParserTokenRange& range,
     const CSSParserContext&,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
-      css_property_parser_helpers::ConsumeIdent<CSSValueID::kRunning,
-                                                CSSValueID::kPaused>,
+  return css_parsing_utils::ConsumeCommaSeparatedList(
+      css_parsing_utils::ConsumeIdent<CSSValueID::kRunning,
+                                      CSSValueID::kPaused>,
       range);
 }
 
@@ -352,7 +349,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext& local_context) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
+  return css_parsing_utils::ConsumeCommaSeparatedList(
       css_parsing_utils::ConsumeAnimationTimeline, range, context);
 }
 
@@ -380,7 +377,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
+  return css_parsing_utils::ConsumeCommaSeparatedList(
       css_parsing_utils::ConsumeAnimationTimingFunction, range, context);
 }
 
@@ -404,15 +401,13 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  CSSValue* width =
-      css_property_parser_helpers::ConsumePositiveInteger(range, context);
+    return css_parsing_utils::ConsumeIdent(range);
+  CSSValue* width = css_parsing_utils::ConsumePositiveInteger(range, context);
   if (!width)
     return nullptr;
-  if (!css_property_parser_helpers::ConsumeSlashIncludingWhitespace(range))
+  if (!css_parsing_utils::ConsumeSlashIncludingWhitespace(range))
     return nullptr;
-  CSSValue* height =
-      css_property_parser_helpers::ConsumePositiveInteger(range, context);
+  CSSValue* height = css_parsing_utils::ConsumePositiveInteger(range, context);
   if (!height)
     return nullptr;
   CSSValueList* list = CSSValueList::CreateSlashSeparated();
@@ -442,7 +437,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeFilterFunctionList(range, context);
+  return css_parsing_utils::ConsumeFilterFunctionList(range, context);
 }
 
 const CSSValue* BackdropFilter::CSSValueFromComputedStyleInternal(
@@ -467,7 +462,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext&,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
+  return css_parsing_utils::ConsumeCommaSeparatedList(
       css_parsing_utils::ConsumeBackgroundAttachment, range);
 }
 
@@ -487,7 +482,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext&,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
+  return css_parsing_utils::ConsumeCommaSeparatedList(
       css_parsing_utils::ConsumeBackgroundBlendMode, range);
 }
 
@@ -529,8 +524,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeColor(
-      range, context, IsQuirksModeBehavior(context.Mode()));
+  return css_parsing_utils::ConsumeColor(range, context,
+                                         IsQuirksModeBehavior(context.Mode()));
 }
 
 const blink::Color BackgroundColor::ColorIncludingFallback(
@@ -558,8 +553,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
-      css_property_parser_helpers::ConsumeImageOrNone, range, context);
+  return css_parsing_utils::ConsumeCommaSeparatedList(
+      css_parsing_utils::ConsumeImageOrNone, range, context);
 }
 
 const CSSValue* BackgroundImage::CSSValueFromComputedStyleInternal(
@@ -598,7 +593,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
+  return css_parsing_utils::ConsumeCommaSeparatedList(
       css_parsing_utils::ConsumePositionLonghand<CSSValueID::kLeft,
                                                  CSSValueID::kRight>,
       range, context);
@@ -618,7 +613,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
+  return css_parsing_utils::ConsumeCommaSeparatedList(
       css_parsing_utils::ConsumePositionLonghand<CSSValueID::kTop,
                                                  CSSValueID::kBottom>,
       range, context);
@@ -658,10 +653,10 @@
   CSSValueID id = range.Peek().Id();
   if (id == CSSValueID::kBaseline || id == CSSValueID::kSub ||
       id == CSSValueID::kSuper)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
   CSSParserContext::ParserModeOverridingScope scope(context, kSVGAttributeMode);
-  return css_property_parser_helpers::ConsumeLengthOrPercent(range, context,
-                                                             kValueRangeAll);
+  return css_parsing_utils::ConsumeLengthOrPercent(range, context,
+                                                   kValueRangeAll);
 }
 
 const CSSValue* BaselineShift::CSSValueFromComputedStyleInternal(
@@ -733,7 +728,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const CSSValue* BorderBlockEndWidth::ParseSingleValue(
@@ -741,14 +736,14 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeBorderWidth(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid);
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* BorderBlockStartColor::ParseSingleValue(
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const CSSValue* BorderBlockStartWidth::ParseSingleValue(
@@ -756,7 +751,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeBorderWidth(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid);
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* BorderBottomColor::ParseSingleValue(
@@ -929,7 +924,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeImageOrNone(range, context);
+  return css_parsing_utils::ConsumeImageOrNone(range, context);
 }
 
 const CSSValue* BorderImageSource::CSSValueFromComputedStyleInternal(
@@ -985,7 +980,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const CSSValue* BorderInlineEndWidth::ParseSingleValue(
@@ -993,14 +988,14 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeBorderWidth(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid);
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* BorderInlineStartColor::ParseSingleValue(
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const CSSValue* BorderInlineStartWidth::ParseSingleValue(
@@ -1008,7 +1003,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeBorderWidth(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid);
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* BorderLeftColor::ParseSingleValue(
@@ -1288,8 +1283,8 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeColor(range, context);
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const blink::Color CaretColor::ColorIncludingFallback(
@@ -1346,10 +1341,9 @@
 CSSValue* ConsumeClipComponent(CSSParserTokenRange& range,
                                const CSSParserContext& context) {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeLength(
-      range, context, kValueRangeAll,
-      css_property_parser_helpers::UnitlessQuirk::kAllow);
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeLength(
+      range, context, kValueRangeAll, css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 }  // namespace
@@ -1358,28 +1352,24 @@
                                        const CSSParserContext& context,
                                        const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
 
   if (range.Peek().FunctionId() != CSSValueID::kRect)
     return nullptr;
 
-  CSSParserTokenRange args =
-      css_property_parser_helpers::ConsumeFunction(range);
+  CSSParserTokenRange args = css_parsing_utils::ConsumeFunction(range);
   // rect(t, r, b, l) || rect(t r b l)
   CSSValue* top = ConsumeClipComponent(args, context);
   if (!top)
     return nullptr;
-  bool needs_comma =
-      css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args);
+  bool needs_comma = css_parsing_utils::ConsumeCommaIncludingWhitespace(args);
   CSSValue* right = ConsumeClipComponent(args, context);
-  if (!right ||
-      (needs_comma &&
-       !css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args)))
+  if (!right || (needs_comma &&
+                 !css_parsing_utils::ConsumeCommaIncludingWhitespace(args)))
     return nullptr;
   CSSValue* bottom = ConsumeClipComponent(args, context);
-  if (!bottom ||
-      (needs_comma &&
-       !css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args)))
+  if (!bottom || (needs_comma &&
+                  !css_parsing_utils::ConsumeCommaIncludingWhitespace(args)))
     return nullptr;
   CSSValue* left = ConsumeClipComponent(args, context);
   if (!left || !args.AtEnd())
@@ -1411,9 +1401,9 @@
                                            const CSSParserContext& context,
                                            const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
   if (cssvalue::CSSURIValue* url =
-          css_property_parser_helpers::ConsumeUrl(range, context))
+          css_parsing_utils::ConsumeUrl(range, context))
     return url;
   return css_parsing_utils::ConsumeBasicShape(range, context);
 }
@@ -1447,8 +1437,8 @@
 const CSSValue* Color::ParseSingleValue(CSSParserTokenRange& range,
                                         const CSSParserContext& context,
                                         const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeColor(
-      range, context, IsQuirksModeBehavior(context.Mode()));
+  return css_parsing_utils::ConsumeColor(range, context,
+                                         IsQuirksModeBehavior(context.Mode()));
 }
 
 const blink::Color Color::ColorIncludingFallback(
@@ -1536,14 +1526,14 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kNormal)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
   if (range.Peek().Id() == CSSValueID::kOnly) {
     // Handle 'only light'
     CSSValueList* values = CSSValueList::CreateSpaceSeparated();
-    values->Append(*css_property_parser_helpers::ConsumeIdent(range));
+    values->Append(*css_parsing_utils::ConsumeIdent(range));
     if (range.Peek().Id() != CSSValueID::kLight)
       return nullptr;
-    values->Append(*css_property_parser_helpers::ConsumeIdent(range));
+    values->Append(*css_parsing_utils::ConsumeIdent(range));
     return values;
   }
 
@@ -1558,7 +1548,7 @@
       return nullptr;
     }
     if (id == CSSValueID::kOnly) {
-      values->Append(*css_property_parser_helpers::ConsumeIdent(range));
+      values->Append(*css_parsing_utils::ConsumeIdent(range));
       // Has to be 'light only'
       if (range.AtEnd() && values->length() == 2 &&
           To<CSSIdentifierValue>(values->Item(0)).GetValueID() ==
@@ -1568,10 +1558,10 @@
       return nullptr;
     }
     CSSValue* value =
-        css_property_parser_helpers::ConsumeIdent<CSSValueID::kDark,
-                                                  CSSValueID::kLight>(range);
+        css_parsing_utils::ConsumeIdent<CSSValueID::kDark, CSSValueID::kLight>(
+            range);
     if (!value)
-      value = css_property_parser_helpers::ConsumeCustomIdent(range, context);
+      value = css_parsing_utils::ConsumeCustomIdent(range, context);
     if (!value)
       return nullptr;
     values->Append(*value);
@@ -1682,7 +1672,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const blink::Color ColumnRuleColor::ColorIncludingFallback(
@@ -1715,8 +1705,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeLineWidth(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid);
+  return css_parsing_utils::ConsumeLineWidth(
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ColumnRuleWidth::CSSValueFromComputedStyleInternal(
@@ -1731,8 +1721,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeIdent<CSSValueID::kAll,
-                                                   CSSValueID::kNone>(range);
+  return css_parsing_utils::ConsumeIdent<CSSValueID::kAll, CSSValueID::kNone>(
+      range);
 }
 
 const CSSValue* ColumnSpan::CSSValueFromComputedStyleInternal(
@@ -1768,11 +1758,11 @@
                                           const CSSParserLocalContext&) const {
   CSSValueID id = range.Peek().Id();
   if (id == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
 
   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
   if (id == CSSValueID::kStrict || id == CSSValueID::kContent) {
-    list->Append(*css_property_parser_helpers::ConsumeIdent(range));
+    list->Append(*css_parsing_utils::ConsumeIdent(range));
     return list;
   }
 
@@ -1783,13 +1773,13 @@
   while (true) {
     id = range.Peek().Id();
     if (id == CSSValueID::kSize && !size)
-      size = css_property_parser_helpers::ConsumeIdent(range);
+      size = css_parsing_utils::ConsumeIdent(range);
     else if (id == CSSValueID::kLayout && !layout)
-      layout = css_property_parser_helpers::ConsumeIdent(range);
+      layout = css_parsing_utils::ConsumeIdent(range);
     else if (id == CSSValueID::kStyle && !style)
-      style = css_property_parser_helpers::ConsumeIdent(range);
+      style = css_parsing_utils::ConsumeIdent(range);
     else if (id == CSSValueID::kPaint && !paint)
-      paint = css_property_parser_helpers::ConsumeIdent(range);
+      paint = css_parsing_utils::ConsumeIdent(range);
     else
       break;
   }
@@ -1838,13 +1828,13 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  CSSValue* width = css_property_parser_helpers::ConsumeLength(
-      range, context, kValueRangeNonNegative);
+    return css_parsing_utils::ConsumeIdent(range);
+  CSSValue* width =
+      css_parsing_utils::ConsumeLength(range, context, kValueRangeNonNegative);
   if (!width)
     return nullptr;
-  CSSValue* height = css_property_parser_helpers::ConsumeLength(
-      range, context, kValueRangeNonNegative);
+  CSSValue* height =
+      css_parsing_utils::ConsumeLength(range, context, kValueRangeNonNegative);
   if (!height)
     height = width;
   return MakeGarbageCollected<CSSValuePair>(width, height,
@@ -1894,7 +1884,7 @@
                                 const CSSParserContext& context,
                                 bool counters) {
   CSSCustomIdentValue* identifier =
-      css_property_parser_helpers::ConsumeCustomIdent(args, context);
+      css_parsing_utils::ConsumeCustomIdent(args, context);
   if (!identifier)
     return nullptr;
 
@@ -1902,7 +1892,7 @@
   if (!counters) {
     separator = MakeGarbageCollected<CSSStringValue>(String());
   } else {
-    if (!css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args) ||
+    if (!css_parsing_utils::ConsumeCommaIncludingWhitespace(args) ||
         args.Peek().GetType() != kStringToken)
       return nullptr;
     separator = MakeGarbageCollected<CSSStringValue>(
@@ -1910,12 +1900,12 @@
   }
 
   CSSIdentifierValue* list_style = nullptr;
-  if (css_property_parser_helpers::ConsumeCommaIncludingWhitespace(args)) {
+  if (css_parsing_utils::ConsumeCommaIncludingWhitespace(args)) {
     CSSValueID id = args.Peek().Id();
     if ((id != CSSValueID::kNone &&
          (id < CSSValueID::kDisc || id > CSSValueID::kKatakanaIroha)))
       return nullptr;
-    list_style = css_property_parser_helpers::ConsumeIdent(args);
+    list_style = css_parsing_utils::ConsumeIdent(args);
   } else {
     list_style = CSSIdentifierValue::Create(CSSValueID::kDecimal);
   }
@@ -1931,39 +1921,36 @@
 const CSSValue* Content::ParseSingleValue(CSSParserTokenRange& range,
                                           const CSSParserContext& context,
                                           const CSSParserLocalContext&) const {
-  if (css_property_parser_helpers::IdentMatches<CSSValueID::kNone,
-                                                CSSValueID::kNormal>(
+  if (css_parsing_utils::IdentMatches<CSSValueID::kNone, CSSValueID::kNormal>(
           range.Peek().Id()))
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
 
   CSSValueList* values = CSSValueList::CreateSpaceSeparated();
   CSSValueList* outer_list = CSSValueList::CreateSlashSeparated();
   bool alt_text_present = false;
   do {
-    CSSValue* parsed_value =
-        css_property_parser_helpers::ConsumeImage(range, context);
+    CSSValue* parsed_value = css_parsing_utils::ConsumeImage(range, context);
     if (!parsed_value) {
-      parsed_value = css_property_parser_helpers::ConsumeIdent<
+      parsed_value = css_parsing_utils::ConsumeIdent<
           CSSValueID::kOpenQuote, CSSValueID::kCloseQuote,
           CSSValueID::kNoOpenQuote, CSSValueID::kNoCloseQuote>(range);
     }
     if (!parsed_value)
-      parsed_value = css_property_parser_helpers::ConsumeString(range);
+      parsed_value = css_parsing_utils::ConsumeString(range);
     if (!parsed_value) {
       if (range.Peek().FunctionId() == CSSValueID::kAttr) {
-        parsed_value = ConsumeAttr(
-            css_property_parser_helpers::ConsumeFunction(range), context);
+        parsed_value =
+            ConsumeAttr(css_parsing_utils::ConsumeFunction(range), context);
       } else if (range.Peek().FunctionId() == CSSValueID::kCounter) {
         parsed_value = ConsumeCounterContent(
-            css_property_parser_helpers::ConsumeFunction(range), context,
-            false);
+            css_parsing_utils::ConsumeFunction(range), context, false);
       } else if (range.Peek().FunctionId() == CSSValueID::kCounters) {
         parsed_value = ConsumeCounterContent(
-            css_property_parser_helpers::ConsumeFunction(range), context, true);
+            css_parsing_utils::ConsumeFunction(range), context, true);
       }
     }
     if (!parsed_value) {
-      if (css_property_parser_helpers::ConsumeSlashIncludingWhitespace(range)) {
+      if (css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
         // No values were parsed before the slash, so nothing to apply the
         // alternative text to.
         if (!values->length())
@@ -1978,8 +1965,7 @@
   } while (!range.AtEnd() && !alt_text_present);
   outer_list->Append(*values);
   if (alt_text_present) {
-    CSSStringValue* alt_text =
-        css_property_parser_helpers::ConsumeString(range);
+    CSSStringValue* alt_text = css_parsing_utils::ConsumeString(range);
     if (!alt_text)
       return nullptr;
     outer_list->Append(*alt_text);
@@ -2138,16 +2124,15 @@
                                          const CSSParserLocalContext&) const {
   bool in_quirks_mode = IsQuirksModeBehavior(context.Mode());
   CSSValueList* list = nullptr;
-  while (
-      CSSValue* image = css_property_parser_helpers::ConsumeImage(
-          range, context,
-          css_property_parser_helpers::ConsumeGeneratedImagePolicy::kForbid)) {
+  while (CSSValue* image = css_parsing_utils::ConsumeImage(
+             range, context,
+             css_parsing_utils::ConsumeGeneratedImagePolicy::kForbid)) {
     double num;
     IntPoint hot_spot(-1, -1);
     bool hot_spot_specified = false;
-    if (css_property_parser_helpers::ConsumeNumberRaw(range, context, num)) {
+    if (css_parsing_utils::ConsumeNumberRaw(range, context, num)) {
       hot_spot.SetX(clampTo<int>(num));
-      if (!css_property_parser_helpers::ConsumeNumberRaw(range, context, num))
+      if (!css_parsing_utils::ConsumeNumberRaw(range, context, num))
         return nullptr;
       hot_spot.SetY(clampTo<int>(num));
       hot_spot_specified = true;
@@ -2158,7 +2143,7 @@
 
     list->Append(*MakeGarbageCollected<cssvalue::CSSCursorImageValue>(
         *image, hot_spot_specified, hot_spot));
-    if (!css_property_parser_helpers::ConsumeCommaIncludingWhitespace(range))
+    if (!css_parsing_utils::ConsumeCommaIncludingWhitespace(range))
       return nullptr;
   }
 
@@ -2181,7 +2166,7 @@
     range.ConsumeIncludingWhitespace();
   } else if ((id >= CSSValueID::kAuto && id <= CSSValueID::kWebkitZoomOut) ||
              id == CSSValueID::kCopy || id == CSSValueID::kNone) {
-    cursor_type = css_property_parser_helpers::ConsumeIdent(range);
+    cursor_type = css_parsing_utils::ConsumeIdent(range);
   } else {
     return nullptr;
   }
@@ -2253,8 +2238,8 @@
 const CSSValue* Cx::ParseSingleValue(CSSParserTokenRange& range,
                                      const CSSParserContext& context,
                                      const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeSVGGeometryPropertyLength(
-      range, context, kValueRangeAll);
+  return css_parsing_utils::ConsumeSVGGeometryPropertyLength(range, context,
+                                                             kValueRangeAll);
 }
 
 const CSSValue* Cx::CSSValueFromComputedStyleInternal(
@@ -2269,8 +2254,8 @@
 const CSSValue* Cy::ParseSingleValue(CSSParserTokenRange& range,
                                      const CSSParserContext& context,
                                      const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeSVGGeometryPropertyLength(
-      range, context, kValueRangeAll);
+  return css_parsing_utils::ConsumeSVGGeometryPropertyLength(range, context,
+                                                             kValueRangeAll);
 }
 
 const CSSValue* Cy::CSSValueFromComputedStyleInternal(
@@ -2328,10 +2313,9 @@
     return nullptr;
 
   CSSParserTokenRange range_copy = range;
-  CSSParserTokenRange args =
-      css_property_parser_helpers::ConsumeFunction(range_copy);
+  CSSParserTokenRange args = css_parsing_utils::ConsumeFunction(range_copy);
   CSSCustomIdentValue* name =
-      css_property_parser_helpers::ConsumeCustomIdent(args, context);
+      css_parsing_utils::ConsumeCustomIdent(args, context);
 
   // If we didn't get a custom-ident or didn't exhaust the function arguments
   // return nothing.
@@ -2424,7 +2408,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeAlphaValue(range, context);
+  return css_parsing_utils::ConsumeAlphaValue(range, context);
 }
 
 const CSSValue* FillOpacity::CSSValueFromComputedStyleInternal(
@@ -2447,7 +2431,7 @@
 const CSSValue* Filter::ParseSingleValue(CSSParserTokenRange& range,
                                          const CSSParserContext& context,
                                          const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeFilterFunctionList(range, context);
+  return css_parsing_utils::ConsumeFilterFunctionList(range, context);
 }
 
 const CSSValue* Filter::CSSValueFromComputedStyleInternal(
@@ -2464,9 +2448,9 @@
     const CSSParserLocalContext&) const {
   // FIXME: Support intrinsic dimensions too.
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative);
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeLengthOrPercent(range, context,
+                                                   kValueRangeNonNegative);
 }
 
 const CSSValue* FlexBasis::CSSValueFromComputedStyleInternal(
@@ -2489,8 +2473,8 @@
 const CSSValue* FlexGrow::ParseSingleValue(CSSParserTokenRange& range,
                                            const CSSParserContext& context,
                                            const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeNumber(range, context,
-                                                    kValueRangeNonNegative);
+  return css_parsing_utils::ConsumeNumber(range, context,
+                                          kValueRangeNonNegative);
 }
 
 const CSSValue* FlexGrow::CSSValueFromComputedStyleInternal(
@@ -2506,8 +2490,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeNumber(range, context,
-                                                    kValueRangeNonNegative);
+  return css_parsing_utils::ConsumeNumber(range, context,
+                                          kValueRangeNonNegative);
 }
 
 const CSSValue* FlexShrink::CSSValueFromComputedStyleInternal(
@@ -2541,7 +2525,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const blink::Color FloodColor::ColorIncludingFallback(
@@ -2566,7 +2550,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeAlphaValue(range, context);
+  return css_parsing_utils::ConsumeAlphaValue(range, context);
 }
 
 const CSSValue* FloodOpacity::CSSValueFromComputedStyleInternal(
@@ -2642,9 +2626,9 @@
     const CSSParserLocalContext&) const {
   DCHECK(RuntimeEnabledFeatures::CSSFontSizeAdjustEnabled());
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeNumber(range, context,
-                                                    kValueRangeNonNegative);
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeNumber(range, context,
+                                          kValueRangeNonNegative);
 }
 
 const CSSValue* FontSizeAdjust::CSSValueFromComputedStyleInternal(
@@ -2663,7 +2647,7 @@
                                            const CSSParserContext& context,
                                            const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeFontSize(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kAllow);
+      range, context, css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 const CSSValue* FontSize::CSSValueFromComputedStyleInternal(
@@ -2708,7 +2692,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeIdent<
+  return css_parsing_utils::ConsumeIdent<
       CSSValueID::kNormal, CSSValueID::kSmallCaps, CSSValueID::kAllSmallCaps,
       CSSValueID::kPetiteCaps, CSSValueID::kAllPetiteCaps, CSSValueID::kUnicase,
       CSSValueID::kTitlingCaps>(range);
@@ -2727,7 +2711,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kNormal)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
 
   FontVariantEastAsianParser east_asian_parser;
   do {
@@ -2753,7 +2737,7 @@
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kNormal ||
       range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
 
   FontVariantLigaturesParser ligatures_parser;
   do {
@@ -2778,7 +2762,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kNormal)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
 
   FontVariantNumericParser numeric_parser;
   do {
@@ -2822,7 +2806,7 @@
   }
 
   double tag_value = 0;
-  if (!css_property_parser_helpers::ConsumeNumberRaw(range, context, tag_value))
+  if (!css_parsing_utils::ConsumeNumberRaw(range, context, tag_value))
     return nullptr;
   return MakeGarbageCollected<cssvalue::CSSFontVariationValue>(
       tag, clampTo<float>(tag_value));
@@ -2835,7 +2819,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kNormal)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
   CSSValueList* variation_settings = CSSValueList::CreateCommaSeparated();
   do {
     cssvalue::CSSFontVariationValue* font_variation_value =
@@ -2843,7 +2827,7 @@
     if (!font_variation_value)
       return nullptr;
     variation_settings->Append(*font_variation_value);
-  } while (css_property_parser_helpers::ConsumeCommaIncludingWhitespace(range));
+  } while (css_parsing_utils::ConsumeCommaIncludingWhitespace(range));
   return variation_settings;
 }
 
@@ -2944,8 +2928,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext& local_context) const {
-  return css_property_parser_helpers::ConsumeColor(
-      range, context, IsQuirksModeBehavior(context.Mode()));
+  return css_parsing_utils::ConsumeColor(range, context,
+                                         IsQuirksModeBehavior(context.Mode()));
 }
 
 const CSSValue* GridAutoColumns::ParseSingleValue(
@@ -2976,14 +2960,14 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   CSSIdentifierValue* row_or_column_value =
-      css_property_parser_helpers::ConsumeIdent<CSSValueID::kRow,
-                                                CSSValueID::kColumn>(range);
+      css_parsing_utils::ConsumeIdent<CSSValueID::kRow, CSSValueID::kColumn>(
+          range);
   CSSIdentifierValue* dense_algorithm =
-      css_property_parser_helpers::ConsumeIdent<CSSValueID::kDense>(range);
+      css_parsing_utils::ConsumeIdent<CSSValueID::kDense>(range);
   if (!row_or_column_value) {
     row_or_column_value =
-        css_property_parser_helpers::ConsumeIdent<CSSValueID::kRow,
-                                                  CSSValueID::kColumn>(range);
+        css_parsing_utils::ConsumeIdent<CSSValueID::kRow, CSSValueID::kColumn>(
+            range);
     if (!row_or_column_value && !dense_algorithm)
       return nullptr;
   }
@@ -3108,7 +3092,7 @@
     const CSSParserContext&,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
 
   NamedGridAreaMap grid_area_map;
   size_t row_count = 0;
@@ -3246,7 +3230,7 @@
                                          const CSSParserContext& context,
                                          const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeWidthOrHeight(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kAllow);
+      range, context, css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 bool Height::IsLayoutDependent(const ComputedStyle* style,
@@ -3281,9 +3265,9 @@
     const CSSParserLocalContext&) const {
   DCHECK(RuntimeEnabledFeatures::ImageOrientationEnabled());
   if (range.Peek().Id() == CSSValueID::kFromImage)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
   if (range.Peek().Id() == CSSValueID::kNone) {
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
   }
   return nullptr;
 }
@@ -3323,7 +3307,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeMarginOrOffset(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid);
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* InsetBlockStart::ParseSingleValue(
@@ -3331,7 +3315,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeMarginOrOffset(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid);
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* InsetInlineEnd::ParseSingleValue(
@@ -3339,7 +3323,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeMarginOrOffset(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid);
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* InsetInlineStart::ParseSingleValue(
@@ -3347,7 +3331,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeMarginOrOffset(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid);
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue*
@@ -3363,8 +3347,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext& local_context) const {
-  return css_property_parser_helpers::ConsumeInternalForcedBackgroundColor(
-      range, context);
+  return css_parsing_utils::ConsumeInternalForcedBackgroundColor(range,
+                                                                 context);
 }
 
 const blink::Color InternalVisitedBackgroundColor::ColorIncludingFallback(
@@ -3392,8 +3376,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext& local_context) const {
-  return css_property_parser_helpers::ConsumeColor(
-      range, context, IsQuirksModeBehavior(context.Mode()));
+  return css_parsing_utils::ConsumeColor(range, context,
+                                         IsQuirksModeBehavior(context.Mode()));
 }
 
 const blink::Color InternalVisitedBorderLeftColor::ColorIncludingFallback(
@@ -3529,7 +3513,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext& local_context) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const blink::Color InternalVisitedOutlineColor::ColorIncludingFallback(
@@ -3567,7 +3551,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext& local_context) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const blink::Color InternalVisitedTextEmphasisColor::ColorIncludingFallback(
@@ -3582,7 +3566,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext& local_context) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const blink::Color InternalVisitedTextFillColor::ColorIncludingFallback(
@@ -3597,7 +3581,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext& local_context) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const blink::Color InternalVisitedTextStrokeColor::ColorIncludingFallback(
@@ -3612,7 +3596,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext& local_context) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const CSSValue* Isolation::CSSValueFromComputedStyleInternal(
@@ -3628,9 +3612,8 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   // justify-content property does not allow the <baseline-position> values.
-  if (css_property_parser_helpers::IdentMatches<
-          CSSValueID::kFirst, CSSValueID::kLast, CSSValueID::kBaseline>(
-          range.Peek().Id()))
+  if (css_parsing_utils::IdentMatches<CSSValueID::kFirst, CSSValueID::kLast,
+                                      CSSValueID::kBaseline>(range.Peek().Id()))
     return nullptr;
   return css_parsing_utils::ConsumeContentDistributionOverflowPosition(
       range, css_parsing_utils::IsContentPositionOrLeftOrRightKeyword);
@@ -3652,19 +3635,15 @@
     const CSSParserLocalContext&) const {
   CSSParserTokenRange range_copy = range;
   // justify-items property does not allow the 'auto' value.
-  if (css_property_parser_helpers::IdentMatches<CSSValueID::kAuto>(
-          range.Peek().Id()))
+  if (css_parsing_utils::IdentMatches<CSSValueID::kAuto>(range.Peek().Id()))
     return nullptr;
   CSSIdentifierValue* legacy =
-      css_property_parser_helpers::ConsumeIdent<CSSValueID::kLegacy>(
-          range_copy);
+      css_parsing_utils::ConsumeIdent<CSSValueID::kLegacy>(range_copy);
   CSSIdentifierValue* position_keyword =
-      css_property_parser_helpers::ConsumeIdent<
-          CSSValueID::kCenter, CSSValueID::kLeft, CSSValueID::kRight>(
-          range_copy);
+      css_parsing_utils::ConsumeIdent<CSSValueID::kCenter, CSSValueID::kLeft,
+                                      CSSValueID::kRight>(range_copy);
   if (!legacy) {
-    legacy = css_property_parser_helpers::ConsumeIdent<CSSValueID::kLegacy>(
-        range_copy);
+    legacy = css_parsing_utils::ConsumeIdent<CSSValueID::kLegacy>(range_copy);
   }
   if (legacy) {
     range = range_copy;
@@ -3752,7 +3731,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const blink::Color LightingColor::ColorIncludingFallback(
@@ -3800,8 +3779,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeLength(range, context,
-                                                    kValueRangeNonNegative);
+  return css_parsing_utils::ConsumeLength(range, context,
+                                          kValueRangeNonNegative);
 }
 
 const CSSValue* LineHeightStep::CSSValueFromComputedStyleInternal(
@@ -3816,7 +3795,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeImageOrNone(range, context);
+  return css_parsing_utils::ConsumeImageOrNone(range, context);
 }
 
 const CSSValue* ListStyleImage::CSSValueFromComputedStyleInternal(
@@ -3849,7 +3828,7 @@
     const CSSParserLocalContext&) const {
   // NOTE: All the keyword values for the list-style-type property are handled
   // by the CSSParserFastPaths.
-  return css_property_parser_helpers::ConsumeString(range);
+  return css_parsing_utils::ConsumeString(range);
 }
 
 const CSSValue* ListStyleType::CSSValueFromComputedStyleInternal(
@@ -3900,7 +3879,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeMarginOrOffset(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid);
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 bool MarginBlockStart::IsLayoutDependent(const ComputedStyle* style,
@@ -3913,7 +3892,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeMarginOrOffset(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid);
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* MarginBottom::ParseSingleValue(
@@ -3921,7 +3900,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeMarginOrOffset(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kAllow);
+      range, context, css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 bool MarginBottom::IsLayoutDependent(const ComputedStyle* style,
@@ -3954,7 +3933,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeMarginOrOffset(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid);
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 bool MarginInlineStart::IsLayoutDependent(const ComputedStyle* style,
@@ -3967,7 +3946,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeMarginOrOffset(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid);
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* MarginLeft::ParseSingleValue(
@@ -3975,7 +3954,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeMarginOrOffset(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kAllow);
+      range, context, css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 bool MarginLeft::IsLayoutDependent(const ComputedStyle* style,
@@ -4003,7 +3982,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeMarginOrOffset(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kAllow);
+      range, context, css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 bool MarginRight::IsLayoutDependent(const ComputedStyle* style,
@@ -4045,7 +4024,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeMarginOrOffset(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kAllow);
+      range, context, css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 bool MarginTop::IsLayoutDependent(const ComputedStyle* style,
@@ -4072,8 +4051,8 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeUrl(range, context);
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeUrl(range, context);
 }
 
 const CSSValue* MarkerEnd::CSSValueFromComputedStyleInternal(
@@ -4089,8 +4068,8 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeUrl(range, context);
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeUrl(range, context);
 }
 
 const CSSValue* MarkerMid::CSSValueFromComputedStyleInternal(
@@ -4106,8 +4085,8 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeUrl(range, context);
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeUrl(range, context);
 }
 
 const CSSValue* MarkerStart::CSSValueFromComputedStyleInternal(
@@ -4123,8 +4102,8 @@
                                        const CSSParserContext& context,
                                        const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeUrl(range, context);
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeUrl(range, context);
 }
 
 const CSSValue* Mask::CSSValueFromComputedStyleInternal(
@@ -4139,7 +4118,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext&,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
+  return css_parsing_utils::ConsumeCommaSeparatedList(
       css_parsing_utils::ConsumeMaskSourceType, range);
 }
 
@@ -4202,7 +4181,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeMaxWidthOrHeight(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kAllow);
+      range, context, css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 const CSSValue* MaxHeight::CSSValueFromComputedStyleInternal(
@@ -4227,7 +4206,7 @@
                                            const CSSParserContext& context,
                                            const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeMaxWidthOrHeight(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kAllow);
+      range, context, css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 const CSSValue* MaxWidth::CSSValueFromComputedStyleInternal(
@@ -4253,7 +4232,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeWidthOrHeight(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kAllow);
+      range, context, css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 const CSSValue* MinHeight::CSSValueFromComputedStyleInternal(
@@ -4278,7 +4257,7 @@
                                            const CSSParserContext& context,
                                            const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeWidthOrHeight(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kAllow);
+      range, context, css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 const CSSValue* MinWidth::CSSValueFromComputedStyleInternal(
@@ -4313,7 +4292,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumePosition(range, context,
-                         css_property_parser_helpers::UnitlessQuirk::kForbid,
+                         css_parsing_utils::UnitlessQuirk::kForbid,
                          base::Optional<WebFeature>());
 }
 
@@ -4336,9 +4315,9 @@
     const CSSParserLocalContext&) const {
   CSSValueID id = range.Peek().Id();
   if (id == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumePosition(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid,
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumePosition(
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid,
       base::Optional<WebFeature>());
 }
 
@@ -4354,8 +4333,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeLengthOrPercent(range, context,
-                                                             kValueRangeAll);
+  return css_parsing_utils::ConsumeLengthOrPercent(range, context,
+                                                   kValueRangeAll);
 }
 
 const CSSValue* OffsetDistance::CSSValueFromComputedStyleInternal(
@@ -4390,9 +4369,9 @@
     const CSSParserLocalContext&) const {
   CSSValueID id = range.Peek().Id();
   if (id == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  CSSValue* value = css_property_parser_helpers::ConsumePosition(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid,
+    return css_parsing_utils::ConsumeIdent(range);
+  CSSValue* value = css_parsing_utils::ConsumePosition(
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid,
       base::Optional<WebFeature>());
 
   // Count when we receive a valid position other than 'auto'.
@@ -4431,7 +4410,7 @@
 const CSSValue* Opacity::ParseSingleValue(CSSParserTokenRange& range,
                                           const CSSParserContext& context,
                                           const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeAlphaValue(range, context);
+  return css_parsing_utils::ConsumeAlphaValue(range, context);
 }
 
 const CSSValue* Opacity::CSSValueFromComputedStyleInternal(
@@ -4446,7 +4425,7 @@
 const CSSValue* Order::ParseSingleValue(CSSParserTokenRange& range,
                                         const CSSParserContext& context,
                                         const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeInteger(range, context);
+  return css_parsing_utils::ConsumeInteger(range, context);
 }
 
 const CSSValue* Order::CSSValueFromComputedStyleInternal(
@@ -4470,7 +4449,7 @@
 const CSSValue* Orphans::ParseSingleValue(CSSParserTokenRange& range,
                                           const CSSParserContext& context,
                                           const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumePositiveInteger(range, context);
+  return css_parsing_utils::ConsumePositiveInteger(range, context);
 }
 
 const CSSValue* Orphans::CSSValueFromComputedStyleInternal(
@@ -4488,8 +4467,8 @@
     const CSSParserLocalContext&) const {
   // Allow the special focus color even in HTML Standard parsing mode.
   if (range.Peek().Id() == CSSValueID::kWebkitFocusRingColor)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeColor(range, context);
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const blink::Color OutlineColor::ColorIncludingFallback(
@@ -4514,8 +4493,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeLength(range, context,
-                                                    kValueRangeAll);
+  return css_parsing_utils::ConsumeLength(range, context, kValueRangeAll);
 }
 
 const CSSValue* OutlineOffset::CSSValueFromComputedStyleInternal(
@@ -4560,8 +4538,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeLineWidth(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid);
+  return css_parsing_utils::ConsumeLineWidth(
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* OutlineWidth::CSSValueFromComputedStyleInternal(
@@ -4629,9 +4607,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative,
-      css_property_parser_helpers::UnitlessQuirk::kForbid);
+  return ConsumeLengthOrPercent(range, context, kValueRangeNonNegative,
+                                css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 bool PaddingBlockStart::IsLayoutDependent(const ComputedStyle* style,
@@ -4643,18 +4620,16 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative,
-      css_property_parser_helpers::UnitlessQuirk::kForbid);
+  return ConsumeLengthOrPercent(range, context, kValueRangeNonNegative,
+                                css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* PaddingBottom::ParseSingleValue(
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative,
-      css_property_parser_helpers::UnitlessQuirk::kAllow);
+  return ConsumeLengthOrPercent(range, context, kValueRangeNonNegative,
+                                css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 bool PaddingBottom::IsLayoutDependent(const ComputedStyle* style,
@@ -4686,9 +4661,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative,
-      css_property_parser_helpers::UnitlessQuirk::kForbid);
+  return ConsumeLengthOrPercent(range, context, kValueRangeNonNegative,
+                                css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 bool PaddingInlineStart::IsLayoutDependent(const ComputedStyle* style,
@@ -4700,18 +4674,16 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative,
-      css_property_parser_helpers::UnitlessQuirk::kForbid);
+  return ConsumeLengthOrPercent(range, context, kValueRangeNonNegative,
+                                css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* PaddingLeft::ParseSingleValue(
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative,
-      css_property_parser_helpers::UnitlessQuirk::kAllow);
+  return ConsumeLengthOrPercent(range, context, kValueRangeNonNegative,
+                                css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 bool PaddingLeft::IsLayoutDependent(const ComputedStyle* style,
@@ -4738,9 +4710,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative,
-      css_property_parser_helpers::UnitlessQuirk::kAllow);
+  return ConsumeLengthOrPercent(range, context, kValueRangeNonNegative,
+                                css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 bool PaddingRight::IsLayoutDependent(const ComputedStyle* style,
@@ -4767,9 +4738,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative,
-      css_property_parser_helpers::UnitlessQuirk::kAllow);
+  return ConsumeLengthOrPercent(range, context, kValueRangeNonNegative,
+                                css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 bool PaddingTop::IsLayoutDependent(const ComputedStyle* style,
@@ -4796,8 +4766,8 @@
                                        const CSSParserContext& context,
                                        const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeCustomIdent(range, context);
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeCustomIdent(range, context);
 }
 
 const CSSValue* Page::CSSValueFromComputedStyleInternal(
@@ -4815,7 +4785,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kNormal)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
 
   Vector<CSSValueID, 3> paint_type_list;
   CSSIdentifierValue* fill = nullptr;
@@ -4824,11 +4794,11 @@
   do {
     CSSValueID id = range.Peek().Id();
     if (id == CSSValueID::kFill && !fill)
-      fill = css_property_parser_helpers::ConsumeIdent(range);
+      fill = css_parsing_utils::ConsumeIdent(range);
     else if (id == CSSValueID::kStroke && !stroke)
-      stroke = css_property_parser_helpers::ConsumeIdent(range);
+      stroke = css_parsing_utils::ConsumeIdent(range);
     else if (id == CSSValueID::kMarkers && !markers)
-      markers = css_property_parser_helpers::ConsumeIdent(range);
+      markers = css_parsing_utils::ConsumeIdent(range);
     else
       return nullptr;
     paint_type_list.push_back(id);
@@ -4905,14 +4875,13 @@
     const CSSParserContext& context,
     const CSSParserLocalContext& localContext) const {
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  CSSPrimitiveValue* parsed_value = css_property_parser_helpers::ConsumeLength(
-      range, context, kValueRangeAll);
+    return css_parsing_utils::ConsumeIdent(range);
+  CSSPrimitiveValue* parsed_value =
+      css_parsing_utils::ConsumeLength(range, context, kValueRangeAll);
   bool use_legacy_parsing = localContext.UseAliasParsing();
   if (!parsed_value && use_legacy_parsing) {
     double perspective;
-    if (!css_property_parser_helpers::ConsumeNumberRaw(range, context,
-                                                       perspective))
+    if (!css_parsing_utils::ConsumeNumberRaw(range, context, perspective))
       return nullptr;
     context.Count(WebFeature::kUnitlessPerspectiveInPerspectiveProperty);
     parsed_value = CSSNumericLiteralValue::Create(
@@ -4939,7 +4908,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumePosition(range, context,
-                         css_property_parser_helpers::UnitlessQuirk::kForbid,
+                         css_parsing_utils::UnitlessQuirk::kForbid,
                          base::Optional<WebFeature>());
 }
 
@@ -5001,11 +4970,10 @@
                                          const CSSParserContext& context,
                                          const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
   CSSValueList* values = CSSValueList::CreateSpaceSeparated();
   while (!range.AtEnd()) {
-    CSSStringValue* parsed_value =
-        css_property_parser_helpers::ConsumeString(range);
+    CSSStringValue* parsed_value = css_parsing_utils::ConsumeString(range);
     if (!parsed_value)
       return nullptr;
     values->Append(*parsed_value);
@@ -5041,7 +5009,7 @@
 const CSSValue* R::ParseSingleValue(CSSParserTokenRange& range,
                                     const CSSParserContext& context,
                                     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeSVGGeometryPropertyLength(
+  return css_parsing_utils::ConsumeSVGGeometryPropertyLength(
       range, context, kValueRangeNonNegative);
 }
 
@@ -5109,22 +5077,22 @@
 
   CSSValueID id = range.Peek().Id();
   if (id == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
 
   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
 
-  CSSValue* rotation = css_property_parser_helpers::ConsumeAngle(
+  CSSValue* rotation = css_parsing_utils::ConsumeAngle(
       range, context, base::Optional<WebFeature>());
 
-  CSSValue* axis = css_property_parser_helpers::ConsumeAxis(range, context);
+  CSSValue* axis = css_parsing_utils::ConsumeAxis(range, context);
   if (axis)
     list->Append(*axis);
   else if (!rotation)
     return nullptr;
 
   if (!rotation) {
-    rotation = css_property_parser_helpers::ConsumeAngle(
-        range, context, base::Optional<WebFeature>());
+    rotation = css_parsing_utils::ConsumeAngle(range, context,
+                                               base::Optional<WebFeature>());
     if (!rotation)
       return nullptr;
   }
@@ -5172,8 +5140,8 @@
                                      const CSSParserContext& context,
                                      const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeSVGGeometryPropertyLength(
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeSVGGeometryPropertyLength(
       range, context, kValueRangeNonNegative);
 }
 
@@ -5190,8 +5158,8 @@
                                      const CSSParserContext& context,
                                      const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeSVGGeometryPropertyLength(
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeSVGGeometryPropertyLength(
       range, context, kValueRangeNonNegative);
 }
 
@@ -5211,21 +5179,21 @@
 
   CSSValueID id = range.Peek().Id();
   if (id == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
 
-  CSSValue* x_scale = css_property_parser_helpers::ConsumeNumber(
-      range, context, kValueRangeAll);
+  CSSValue* x_scale =
+      css_parsing_utils::ConsumeNumber(range, context, kValueRangeAll);
   if (!x_scale)
     return nullptr;
 
   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
   list->Append(*x_scale);
 
-  CSSValue* y_scale = css_property_parser_helpers::ConsumeNumber(
-      range, context, kValueRangeAll);
+  CSSValue* y_scale =
+      css_parsing_utils::ConsumeNumber(range, context, kValueRangeAll);
   if (y_scale) {
-    CSSValue* z_scale = css_property_parser_helpers::ConsumeNumber(
-        range, context, kValueRangeAll);
+    CSSValue* z_scale =
+        css_parsing_utils::ConsumeNumber(range, context, kValueRangeAll);
     if (z_scale) {
       list->Append(*y_scale);
       list->Append(*z_scale);
@@ -5282,11 +5250,11 @@
   if ((id == CSSValueID::kPanX || id == CSSValueID::kPanRight ||
        id == CSSValueID::kPanLeft) &&
       !*pan_x) {
-    *pan_x = css_property_parser_helpers::ConsumeIdent(range);
+    *pan_x = css_parsing_utils::ConsumeIdent(range);
   } else if ((id == CSSValueID::kPanY || id == CSSValueID::kPanDown ||
               id == CSSValueID::kPanUp) &&
              !*pan_y) {
-    *pan_y = css_property_parser_helpers::ConsumeIdent(range);
+    *pan_y = css_parsing_utils::ConsumeIdent(range);
   } else {
     return false;
   }
@@ -5302,7 +5270,7 @@
   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
   CSSValueID id = range.Peek().Id();
   if (id == CSSValueID::kAuto || id == CSSValueID::kNone) {
-    list->Append(*css_property_parser_helpers::ConsumeIdent(range));
+    list->Append(*css_parsing_utils::ConsumeIdent(range));
     return list;
   }
 
@@ -5334,7 +5302,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumeLength(range, context, kValueRangeAll,
-                       css_property_parser_helpers::UnitlessQuirk::kForbid);
+                       css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ScrollMarginBlockStart::ParseSingleValue(
@@ -5342,7 +5310,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumeLength(range, context, kValueRangeAll,
-                       css_property_parser_helpers::UnitlessQuirk::kForbid);
+                       css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ScrollMarginBottom::ParseSingleValue(
@@ -5350,7 +5318,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumeLength(range, context, kValueRangeAll,
-                       css_property_parser_helpers::UnitlessQuirk::kForbid);
+                       css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ScrollMarginBottom::CSSValueFromComputedStyleInternal(
@@ -5366,7 +5334,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumeLength(range, context, kValueRangeAll,
-                       css_property_parser_helpers::UnitlessQuirk::kForbid);
+                       css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ScrollMarginInlineStart::ParseSingleValue(
@@ -5374,7 +5342,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumeLength(range, context, kValueRangeAll,
-                       css_property_parser_helpers::UnitlessQuirk::kForbid);
+                       css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ScrollMarginLeft::ParseSingleValue(
@@ -5382,7 +5350,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumeLength(range, context, kValueRangeAll,
-                       css_property_parser_helpers::UnitlessQuirk::kForbid);
+                       css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ScrollMarginLeft::CSSValueFromComputedStyleInternal(
@@ -5398,7 +5366,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumeLength(range, context, kValueRangeAll,
-                       css_property_parser_helpers::UnitlessQuirk::kForbid);
+                       css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ScrollMarginRight::CSSValueFromComputedStyleInternal(
@@ -5414,7 +5382,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   return ConsumeLength(range, context, kValueRangeAll,
-                       css_property_parser_helpers::UnitlessQuirk::kForbid);
+                       css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* ScrollMarginTop::CSSValueFromComputedStyleInternal(
@@ -5521,17 +5489,19 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  CSSValue* block_value = css_property_parser_helpers::ConsumeIdent<
-      CSSValueID::kNone, CSSValueID::kStart, CSSValueID::kEnd,
-      CSSValueID::kCenter>(range);
+  CSSValue* block_value =
+      css_parsing_utils::ConsumeIdent<CSSValueID::kNone, CSSValueID::kStart,
+                                      CSSValueID::kEnd, CSSValueID::kCenter>(
+          range);
   if (!block_value)
     return nullptr;
   if (range.AtEnd())
     return block_value;
 
-  CSSValue* inline_value = css_property_parser_helpers::ConsumeIdent<
-      CSSValueID::kNone, CSSValueID::kStart, CSSValueID::kEnd,
-      CSSValueID::kCenter>(range);
+  CSSValue* inline_value =
+      css_parsing_utils::ConsumeIdent<CSSValueID::kNone, CSSValueID::kStart,
+                                      CSSValueID::kEnd, CSSValueID::kCenter>(
+          range);
   if (!inline_value)
     return block_value;
   auto* pair = MakeGarbageCollected<CSSValuePair>(
@@ -5565,7 +5535,7 @@
       axis_id != CSSValueID::kY && axis_id != CSSValueID::kBlock &&
       axis_id != CSSValueID::kInline && axis_id != CSSValueID::kBoth)
     return nullptr;
-  CSSValue* axis_value = css_property_parser_helpers::ConsumeIdent(range);
+  CSSValue* axis_value = css_parsing_utils::ConsumeIdent(range);
   if (range.AtEnd() || axis_id == CSSValueID::kNone)
     return axis_value;
 
@@ -5573,7 +5543,7 @@
   if (strictness_id != CSSValueID::kProximity &&
       strictness_id != CSSValueID::kMandatory)
     return axis_value;
-  CSSValue* strictness_value = css_property_parser_helpers::ConsumeIdent(range);
+  CSSValue* strictness_value = css_parsing_utils::ConsumeIdent(range);
   if (strictness_id == CSSValueID::kProximity)
     return axis_value;  // Shortest serialization.
   auto* pair = MakeGarbageCollected<CSSValuePair>(
@@ -5594,7 +5564,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeAlphaValue(range, context);
+  return css_parsing_utils::ConsumeAlphaValue(range, context);
 }
 
 const CSSValue* ShapeImageThreshold::CSSValueFromComputedStyleInternal(
@@ -5610,8 +5580,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeLengthOrPercent(
-      range, context, kValueRangeNonNegative);
+  return css_parsing_utils::ConsumeLengthOrPercent(range, context,
+                                                   kValueRangeNonNegative);
 }
 
 const CSSValue* ShapeMargin::CSSValueFromComputedStyleInternal(
@@ -5627,15 +5597,15 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   if (CSSValue* image_value =
-          css_property_parser_helpers::ConsumeImageOrNone(range, context))
+          css_parsing_utils::ConsumeImageOrNone(range, context))
     return image_value;
   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
-  CSSValue* box_value = css_property_parser_helpers::ConsumeShapeBox(range);
+  CSSValue* box_value = css_parsing_utils::ConsumeShapeBox(range);
   if (CSSValue* shape_value =
           css_parsing_utils::ConsumeBasicShape(range, context)) {
     list->Append(*shape_value);
     if (!box_value) {
-      box_value = css_property_parser_helpers::ConsumeShapeBox(range);
+      box_value = css_parsing_utils::ConsumeShapeBox(range);
     }
   }
   if (box_value)
@@ -5663,7 +5633,7 @@
 }
 
 static CSSValue* ConsumePageSize(CSSParserTokenRange& range) {
-  return css_property_parser_helpers::ConsumeIdent<
+  return css_parsing_utils::ConsumeIdent<
       CSSValueID::kA3, CSSValueID::kA4, CSSValueID::kA5, CSSValueID::kB4,
       CSSValueID::kB5, CSSValueID::kJisB5, CSSValueID::kJisB4,
       CSSValueID::kLedger, CSSValueID::kLegal, CSSValueID::kLetter>(range);
@@ -5709,14 +5679,14 @@
   CSSValueList* result = CSSValueList::CreateSpaceSeparated();
 
   if (range.Peek().Id() == CSSValueID::kAuto) {
-    result->Append(*css_property_parser_helpers::ConsumeIdent(range));
+    result->Append(*css_parsing_utils::ConsumeIdent(range));
     return result;
   }
 
-  if (CSSValue* width = css_property_parser_helpers::ConsumeLength(
+  if (CSSValue* width = css_parsing_utils::ConsumeLength(
           range, context, kValueRangeNonNegative)) {
-    CSSValue* height = css_property_parser_helpers::ConsumeLength(
-        range, context, kValueRangeNonNegative);
+    CSSValue* height = css_parsing_utils::ConsumeLength(range, context,
+                                                        kValueRangeNonNegative);
     result->Append(*width);
     if (height)
       result->Append(*height);
@@ -5725,8 +5695,8 @@
 
   CSSValue* page_size = ConsumePageSize(range);
   CSSValue* orientation =
-      css_property_parser_helpers::ConsumeIdent<CSSValueID::kPortrait,
-                                                CSSValueID::kLandscape>(range);
+      css_parsing_utils::ConsumeIdent<CSSValueID::kPortrait,
+                                      CSSValueID::kLandscape>(range);
   if (!page_size)
     page_size = ConsumePageSize(range);
 
@@ -5818,7 +5788,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const blink::Color StopColor::ColorIncludingFallback(
@@ -5842,7 +5812,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeAlphaValue(range, context);
+  return css_parsing_utils::ConsumeAlphaValue(range, context);
 }
 
 const CSSValue* StopOpacity::CSSValueFromComputedStyleInternal(
@@ -5875,17 +5845,15 @@
     const CSSParserLocalContext&) const {
   CSSValueID id = range.Peek().Id();
   if (id == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
 
   CSSParserContext::ParserModeOverridingScope scope(context, kSVGAttributeMode);
   CSSValueList* dashes = CSSValueList::CreateCommaSeparated();
   do {
-    CSSPrimitiveValue* dash =
-        css_property_parser_helpers::ConsumeLengthOrPercent(
-            range, context, kValueRangeNonNegative);
-    if (!dash ||
-        (css_property_parser_helpers::ConsumeCommaIncludingWhitespace(range) &&
-         range.AtEnd()))
+    CSSPrimitiveValue* dash = css_parsing_utils::ConsumeLengthOrPercent(
+        range, context, kValueRangeNonNegative);
+    if (!dash || (css_parsing_utils::ConsumeCommaIncludingWhitespace(range) &&
+                  range.AtEnd()))
       return nullptr;
     dashes->Append(*dash);
   } while (!range.AtEnd());
@@ -5906,9 +5874,9 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   CSSParserContext::ParserModeOverridingScope scope(context, kSVGAttributeMode);
-  return css_property_parser_helpers::ConsumeLengthOrPercent(
+  return css_parsing_utils::ConsumeLengthOrPercent(
       range, context, kValueRangeAll,
-      css_property_parser_helpers::UnitlessQuirk::kForbid);
+      css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* StrokeDashoffset::CSSValueFromComputedStyleInternal(
@@ -5940,8 +5908,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeNumber(range, context,
-                                                    kValueRangeNonNegative);
+  return css_parsing_utils::ConsumeNumber(range, context,
+                                          kValueRangeNonNegative);
 }
 
 const CSSValue* StrokeMiterlimit::CSSValueFromComputedStyleInternal(
@@ -5957,7 +5925,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeAlphaValue(range, context);
+  return css_parsing_utils::ConsumeAlphaValue(range, context);
 }
 
 const CSSValue* StrokeOpacity::CSSValueFromComputedStyleInternal(
@@ -5974,9 +5942,9 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   CSSParserContext::ParserModeOverridingScope scope(context, kSVGAttributeMode);
-  return css_property_parser_helpers::ConsumeLengthOrPercent(
+  return css_parsing_utils::ConsumeLengthOrPercent(
       range, context, kValueRangeNonNegative,
-      css_property_parser_helpers::UnitlessQuirk::kForbid);
+      css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* StrokeWidth::CSSValueFromComputedStyleInternal(
@@ -6006,23 +5974,23 @@
       !RuntimeEnabledFeatures::CSSContentVisibilityHiddenMatchableEnabled()) {
     return nullptr;
   }
-  if (!css_property_parser_helpers::IdentMatches<
-          CSSValueID::kVisible, CSSValueID::kAuto, CSSValueID::kHidden,
-          CSSValueID::kHiddenMatchable>(id)) {
+  if (!css_parsing_utils::IdentMatches<CSSValueID::kVisible, CSSValueID::kAuto,
+                                       CSSValueID::kHidden,
+                                       CSSValueID::kHiddenMatchable>(id)) {
     return nullptr;
   }
-  return css_property_parser_helpers::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeIdent(range);
 }
 
 const CSSValue* TabSize::ParseSingleValue(CSSParserTokenRange& range,
                                           const CSSParserContext& context,
                                           const CSSParserLocalContext&) const {
-  CSSPrimitiveValue* parsed_value = css_property_parser_helpers::ConsumeNumber(
-      range, context, kValueRangeNonNegative);
+  CSSPrimitiveValue* parsed_value =
+      css_parsing_utils::ConsumeNumber(range, context, kValueRangeNonNegative);
   if (parsed_value)
     return parsed_value;
-  return css_property_parser_helpers::ConsumeLength(range, context,
-                                                    kValueRangeNonNegative);
+  return css_parsing_utils::ConsumeLength(range, context,
+                                          kValueRangeNonNegative);
 }
 
 const CSSValue* TabSize::CSSValueFromComputedStyleInternal(
@@ -6107,7 +6075,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const blink::Color TextDecorationColor::ColorIncludingFallback(
@@ -6166,13 +6134,12 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   DCHECK(RuntimeEnabledFeatures::UnderlineOffsetThicknessEnabled());
-  if (auto* ident =
-          css_property_parser_helpers::ConsumeIdent<CSSValueID::kFromFont,
+  if (auto* ident = css_parsing_utils::ConsumeIdent<CSSValueID::kFromFont,
                                                     CSSValueID::kAuto>(range)) {
     return ident;
   }
-  return css_property_parser_helpers::ConsumeLengthOrPercent(range, context,
-                                                             kValueRangeAll);
+  return css_parsing_utils::ConsumeLengthOrPercent(range, context,
+                                                   kValueRangeAll);
 }
 
 const CSSValue* TextDecorationThickness::CSSValueFromComputedStyleInternal(
@@ -6198,9 +6165,9 @@
   CSSValue* each_line = nullptr;
   do {
     if (!length_percentage) {
-      length_percentage = css_property_parser_helpers::ConsumeLengthOrPercent(
+      length_percentage = css_parsing_utils::ConsumeLengthOrPercent(
           range, context, kValueRangeAll,
-          css_property_parser_helpers::UnitlessQuirk::kAllow);
+          css_parsing_utils::UnitlessQuirk::kAllow);
       if (length_percentage) {
         continue;
       }
@@ -6209,11 +6176,11 @@
     if (RuntimeEnabledFeatures::CSS3TextEnabled()) {
       CSSValueID id = range.Peek().Id();
       if (!hanging && id == CSSValueID::kHanging) {
-        hanging = css_property_parser_helpers::ConsumeIdent(range);
+        hanging = css_parsing_utils::ConsumeIdent(range);
         continue;
       }
       if (!each_line && id == CSSValueID::kEachLine) {
-        each_line = css_property_parser_helpers::ConsumeIdent(range);
+        each_line = css_parsing_utils::ConsumeIdent(range);
         continue;
       }
     }
@@ -6365,11 +6332,11 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumePercent(range, context,
-                                                     kValueRangeNonNegative);
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumePercent(range, context,
+                                           kValueRangeNonNegative);
 }
 
 const CSSValue* TextSizeAdjust::CSSValueFromComputedStyleInternal(
@@ -6399,25 +6366,22 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
 
   CSSIdentifierValue* from_font_or_under_value =
       RuntimeEnabledFeatures::UnderlineOffsetThicknessEnabled()
-          ? css_property_parser_helpers::ConsumeIdent<CSSValueID::kFromFont,
-                                                      CSSValueID::kUnder>(range)
-          : css_property_parser_helpers::ConsumeIdent<CSSValueID::kUnder>(
-                range);
+          ? css_parsing_utils::ConsumeIdent<CSSValueID::kFromFont,
+                                            CSSValueID::kUnder>(range)
+          : css_parsing_utils::ConsumeIdent<CSSValueID::kUnder>(range);
   CSSIdentifierValue* left_or_right_value =
-      css_property_parser_helpers::ConsumeIdent<CSSValueID::kLeft,
-                                                CSSValueID::kRight>(range);
+      css_parsing_utils::ConsumeIdent<CSSValueID::kLeft, CSSValueID::kRight>(
+          range);
   if (left_or_right_value && !from_font_or_under_value) {
     from_font_or_under_value =
         RuntimeEnabledFeatures::UnderlineOffsetThicknessEnabled()
-            ? css_property_parser_helpers::ConsumeIdent<CSSValueID::kFromFont,
-                                                        CSSValueID::kUnder>(
-                  range)
-            : css_property_parser_helpers::ConsumeIdent<CSSValueID::kUnder>(
-                  range);
+            ? css_parsing_utils::ConsumeIdent<CSSValueID::kFromFont,
+                                              CSSValueID::kUnder>(range)
+            : css_parsing_utils::ConsumeIdent<CSSValueID::kUnder>(range);
   }
   if (!from_font_or_under_value && !left_or_right_value)
     return nullptr;
@@ -6467,9 +6431,9 @@
     const CSSParserLocalContext&) const {
   DCHECK(RuntimeEnabledFeatures::UnderlineOffsetThicknessEnabled());
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeLengthOrPercent(range, context,
-                                                             kValueRangeAll);
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeLengthOrPercent(range, context,
+                                                   kValueRangeAll);
 }
 
 const CSSValue* TextUnderlineOffset::CSSValueFromComputedStyleInternal(
@@ -6514,13 +6478,13 @@
   if ((id == CSSValueID::kPanX || id == CSSValueID::kPanRight ||
        id == CSSValueID::kPanLeft) &&
       !pan_x) {
-    pan_x = css_property_parser_helpers::ConsumeIdent(range);
+    pan_x = css_parsing_utils::ConsumeIdent(range);
   } else if ((id == CSSValueID::kPanY || id == CSSValueID::kPanDown ||
               id == CSSValueID::kPanUp) &&
              !pan_y) {
-    pan_y = css_property_parser_helpers::ConsumeIdent(range);
+    pan_y = css_parsing_utils::ConsumeIdent(range);
   } else if (id == CSSValueID::kPinchZoom && !pinch_zoom) {
-    pinch_zoom = css_property_parser_helpers::ConsumeIdent(range);
+    pinch_zoom = css_parsing_utils::ConsumeIdent(range);
   } else {
     return false;
   }
@@ -6537,7 +6501,7 @@
   CSSValueID id = range.Peek().Id();
   if (id == CSSValueID::kAuto || id == CSSValueID::kNone ||
       id == CSSValueID::kManipulation) {
-    list->Append(*css_property_parser_helpers::ConsumeIdent(range));
+    list->Append(*css_parsing_utils::ConsumeIdent(range));
     return list;
   }
 
@@ -6603,14 +6567,14 @@
     const CSSParserLocalContext&) const {
   CSSValue* result_x = nullptr;
   CSSValue* result_y = nullptr;
-  if (css_property_parser_helpers::ConsumeOneOrTwoValuedPosition(
-          range, context, css_property_parser_helpers::UnitlessQuirk::kForbid,
-          result_x, result_y)) {
+  if (css_parsing_utils::ConsumeOneOrTwoValuedPosition(
+          range, context, css_parsing_utils::UnitlessQuirk::kForbid, result_x,
+          result_y)) {
     CSSValueList* list = CSSValueList::CreateSpaceSeparated();
     list->Append(*result_x);
     list->Append(*result_y);
-    CSSValue* result_z = css_property_parser_helpers::ConsumeLength(
-        range, context, kValueRangeAll);
+    CSSValue* result_z =
+        css_parsing_utils::ConsumeLength(range, context, kValueRangeAll);
     if (result_z)
       list->Append(*result_z);
     return list;
@@ -6664,8 +6628,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
-      css_property_parser_helpers::ConsumeTime, range, context, kValueRangeAll);
+  return css_parsing_utils::ConsumeCommaSeparatedList(
+      css_parsing_utils::ConsumeTime, range, context, kValueRangeAll);
 }
 
 const CSSValue* TransitionDelay::CSSValueFromComputedStyleInternal(
@@ -6688,9 +6652,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
-      css_property_parser_helpers::ConsumeTime, range, context,
-      kValueRangeNonNegative);
+  return css_parsing_utils::ConsumeCommaSeparatedList(
+      css_parsing_utils::ConsumeTime, range, context, kValueRangeNonNegative);
 }
 
 const CSSValue* TransitionDuration::CSSValueFromComputedStyleInternal(
@@ -6713,7 +6676,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  CSSValueList* list = css_property_parser_helpers::ConsumeCommaSeparatedList(
+  CSSValueList* list = css_parsing_utils::ConsumeCommaSeparatedList(
       css_parsing_utils::ConsumeTransitionProperty, range, context);
   if (!list || !css_parsing_utils::IsValidPropertyList(*list))
     return nullptr;
@@ -6738,7 +6701,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
+  return css_parsing_utils::ConsumeCommaSeparatedList(
       css_parsing_utils::ConsumeAnimationTimingFunction, range, context);
 }
 
@@ -6764,20 +6727,19 @@
   DCHECK(RuntimeEnabledFeatures::CSSIndependentTransformPropertiesEnabled());
   CSSValueID id = range.Peek().Id();
   if (id == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
 
-  CSSValue* translate_x = css_property_parser_helpers::ConsumeLengthOrPercent(
-      range, context, kValueRangeAll);
+  CSSValue* translate_x =
+      css_parsing_utils::ConsumeLengthOrPercent(range, context, kValueRangeAll);
   if (!translate_x)
     return nullptr;
   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
   list->Append(*translate_x);
   CSSPrimitiveValue* translate_y =
-      css_property_parser_helpers::ConsumeLengthOrPercent(range, context,
-                                                          kValueRangeAll);
+      css_parsing_utils::ConsumeLengthOrPercent(range, context, kValueRangeAll);
   if (translate_y) {
-    CSSValue* translate_z = css_property_parser_helpers::ConsumeLength(
-        range, context, kValueRangeAll);
+    CSSValue* translate_z =
+        css_parsing_utils::ConsumeLength(range, context, kValueRangeAll);
     if (translate_y->IsZero() && !translate_z)
       return list;
 
@@ -6846,12 +6808,12 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  CSSValue* parsed_value = css_property_parser_helpers::ConsumeIdentRange(
+  CSSValue* parsed_value = css_parsing_utils::ConsumeIdentRange(
       range, CSSValueID::kBaseline, CSSValueID::kWebkitBaselineMiddle);
   if (!parsed_value) {
-    parsed_value = css_property_parser_helpers::ConsumeLengthOrPercent(
+    parsed_value = css_parsing_utils::ConsumeLengthOrPercent(
         range, context, kValueRangeAll,
-        css_property_parser_helpers::UnitlessQuirk::kAllow);
+        css_parsing_utils::UnitlessQuirk::kAllow);
   }
   return parsed_value;
 }
@@ -6954,9 +6916,8 @@
                                                          context.Mode())) {
     if (local_context.UseAliasParsing())
       property = CSSPropertyID::kAliasWebkitAppearance;
-    css_property_parser_helpers::CountKeywordOnlyPropertyUsage(property,
-                                                               context, id);
-    return css_property_parser_helpers::ConsumeIdent(range);
+    css_parsing_utils::CountKeywordOnlyPropertyUsage(property, context, id);
+    return css_parsing_utils::ConsumeIdent(range);
   }
   return nullptr;
 }
@@ -6973,8 +6934,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeLength(range, context,
-                                                    kValueRangeNonNegative);
+  return css_parsing_utils::ConsumeLength(range, context,
+                                          kValueRangeNonNegative);
 }
 
 const CSSValue*
@@ -7014,8 +6975,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeLength(range, context,
-                                                    kValueRangeNonNegative);
+  return css_parsing_utils::ConsumeLength(range, context,
+                                          kValueRangeNonNegative);
 }
 
 const CSSValue* WebkitBorderVerticalSpacing::CSSValueFromComputedStyleInternal(
@@ -7056,8 +7017,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeNumber(range, context,
-                                                    kValueRangeAll);
+  return css_parsing_utils::ConsumeNumber(range, context, kValueRangeAll);
 }
 
 const CSSValue* WebkitBoxFlex::CSSValueFromComputedStyleInternal(
@@ -7073,7 +7033,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumePositiveInteger(range, context);
+  return css_parsing_utils::ConsumePositiveInteger(range, context);
 }
 
 const CSSValue* WebkitBoxOrdinalGroup::CSSValueFromComputedStyleInternal(
@@ -7105,9 +7065,10 @@
 
 CSSValue* ConsumeReflect(CSSParserTokenRange& range,
                          const CSSParserContext& context) {
-  CSSIdentifierValue* direction = css_property_parser_helpers::ConsumeIdent<
-      CSSValueID::kAbove, CSSValueID::kBelow, CSSValueID::kLeft,
-      CSSValueID::kRight>(range);
+  CSSIdentifierValue* direction =
+      css_parsing_utils::ConsumeIdent<CSSValueID::kAbove, CSSValueID::kBelow,
+                                      CSSValueID::kLeft, CSSValueID::kRight>(
+          range);
   if (!direction)
     return nullptr;
 
@@ -7116,9 +7077,8 @@
     offset =
         CSSNumericLiteralValue::Create(0, CSSPrimitiveValue::UnitType::kPixels);
   } else {
-    offset = ConsumeLengthOrPercent(
-        range, context, kValueRangeAll,
-        css_property_parser_helpers::UnitlessQuirk::kForbid);
+    offset = ConsumeLengthOrPercent(range, context, kValueRangeAll,
+                                    css_parsing_utils::UnitlessQuirk::kForbid);
     if (!offset)
       return nullptr;
   }
@@ -7155,9 +7115,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeLength(
-      range, context, kValueRangeAll,
-      css_property_parser_helpers::UnitlessQuirk::kAllow);
+  return css_parsing_utils::ConsumeLength(
+      range, context, kValueRangeAll, css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 const CSSValue* WebkitFontSmoothing::CSSValueFromComputedStyleInternal(
@@ -7173,8 +7132,8 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeString(range);
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeString(range);
 }
 
 const CSSValue* WebkitHighlight::CSSValueFromComputedStyleInternal(
@@ -7192,8 +7151,8 @@
     const CSSParserContext&,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeString(range);
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeString(range);
 }
 
 const CSSValue* WebkitHyphenateCharacter::CSSValueFromComputedStyleInternal(
@@ -7219,7 +7178,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   // When specifying number of lines, don't allow 0 as a valid value.
-  return css_property_parser_helpers::ConsumePositiveInteger(range, context);
+  return css_parsing_utils::ConsumePositiveInteger(range, context);
 }
 
 const CSSValue* WebkitLineClamp::CSSValueFromComputedStyleInternal(
@@ -7238,8 +7197,8 @@
     const CSSParserContext&,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeString(range);
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeString(range);
 }
 
 const CSSValue* WebkitLocale::CSSValueFromComputedStyleInternal(
@@ -7314,7 +7273,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeImageOrNone(range, context);
+  return css_parsing_utils::ConsumeImageOrNone(range, context);
 }
 
 const CSSValue* WebkitMaskBoxImageSource::CSSValueFromComputedStyleInternal(
@@ -7355,7 +7314,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext&,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
+  return css_parsing_utils::ConsumeCommaSeparatedList(
       css_parsing_utils::ConsumePrefixedBackgroundBox, range,
       css_parsing_utils::AllowTextValue::kAllow);
 }
@@ -7378,7 +7337,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext&,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
+  return css_parsing_utils::ConsumeCommaSeparatedList(
       css_parsing_utils::ConsumeBackgroundComposite, range);
 }
 
@@ -7398,8 +7357,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
-      css_property_parser_helpers::ConsumeImageOrNone, range, context);
+  return css_parsing_utils::ConsumeCommaSeparatedList(
+      css_parsing_utils::ConsumeImageOrNone, range, context);
 }
 
 const CSSValue* WebkitMaskImage::CSSValueFromComputedStyleInternal(
@@ -7416,7 +7375,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext&,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
+  return css_parsing_utils::ConsumeCommaSeparatedList(
       css_parsing_utils::ConsumePrefixedBackgroundBox, range,
       css_parsing_utils::AllowTextValue::kForbid);
 }
@@ -7439,7 +7398,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
+  return css_parsing_utils::ConsumeCommaSeparatedList(
       css_parsing_utils::ConsumePositionLonghand<CSSValueID::kLeft,
                                                  CSSValueID::kRight>,
       range, context);
@@ -7459,7 +7418,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeCommaSeparatedList(
+  return css_parsing_utils::ConsumeCommaSeparatedList(
       css_parsing_utils::ConsumePositionLonghand<CSSValueID::kTop,
                                                  CSSValueID::kBottom>,
       range, context);
@@ -7555,7 +7514,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const blink::Color WebkitTapHighlightColor::ColorIncludingFallback(
@@ -7607,7 +7566,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const blink::Color WebkitTextEmphasisColor::ColorIncludingFallback(
@@ -7633,15 +7592,16 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   CSSIdentifierValue* values[2] = {
-      css_property_parser_helpers::ConsumeIdent<
-          CSSValueID::kOver, CSSValueID::kUnder, CSSValueID::kRight,
-          CSSValueID::kLeft>(range),
+      css_parsing_utils::ConsumeIdent<CSSValueID::kOver, CSSValueID::kUnder,
+                                      CSSValueID::kRight, CSSValueID::kLeft>(
+          range),
       nullptr};
   if (!values[0])
     return nullptr;
-  values[1] = css_property_parser_helpers::ConsumeIdent<
-      CSSValueID::kOver, CSSValueID::kUnder, CSSValueID::kRight,
-      CSSValueID::kLeft>(range);
+  values[1] =
+      css_parsing_utils::ConsumeIdent<CSSValueID::kOver, CSSValueID::kUnder,
+                                      CSSValueID::kRight, CSSValueID::kLeft>(
+          range);
   CSSIdentifierValue* over_under = nullptr;
   CSSIdentifierValue* left_right = nullptr;
 
@@ -7709,21 +7669,21 @@
     const CSSParserLocalContext&) const {
   CSSValueID id = range.Peek().Id();
   if (id == CSSValueID::kNone)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
 
-  if (CSSValue* text_emphasis_style =
-          css_property_parser_helpers::ConsumeString(range))
+  if (CSSValue* text_emphasis_style = css_parsing_utils::ConsumeString(range))
     return text_emphasis_style;
 
   CSSIdentifierValue* fill =
-      css_property_parser_helpers::ConsumeIdent<CSSValueID::kFilled,
-                                                CSSValueID::kOpen>(range);
-  CSSIdentifierValue* shape = css_property_parser_helpers::ConsumeIdent<
+      css_parsing_utils::ConsumeIdent<CSSValueID::kFilled, CSSValueID::kOpen>(
+          range);
+  CSSIdentifierValue* shape = css_parsing_utils::ConsumeIdent<
       CSSValueID::kDot, CSSValueID::kCircle, CSSValueID::kDoubleCircle,
       CSSValueID::kTriangle, CSSValueID::kSesame>(range);
   if (!fill) {
-    fill = css_property_parser_helpers::ConsumeIdent<CSSValueID::kFilled,
-                                                     CSSValueID::kOpen>(range);
+    fill =
+        css_parsing_utils::ConsumeIdent<CSSValueID::kFilled, CSSValueID::kOpen>(
+            range);
   }
   if (fill && shape) {
     CSSValueList* parsed_values = CSSValueList::CreateSpaceSeparated();
@@ -7832,7 +7792,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const blink::Color WebkitTextFillColor::ColorIncludingFallback(
@@ -7888,7 +7848,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeColor(range, context);
+  return css_parsing_utils::ConsumeColor(range, context);
 }
 
 const blink::Color WebkitTextStrokeColor::ColorIncludingFallback(
@@ -7911,8 +7871,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeLineWidth(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kForbid);
+  return css_parsing_utils::ConsumeLineWidth(
+      range, context, css_parsing_utils::UnitlessQuirk::kForbid);
 }
 
 const CSSValue* WebkitTextStrokeWidth::CSSValueFromComputedStyleInternal(
@@ -7945,8 +7905,7 @@
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeLength(range, context,
-                                                    kValueRangeAll);
+  return css_parsing_utils::ConsumeLength(range, context, kValueRangeAll);
 }
 
 const CSSValue* WebkitUserDrag::CSSValueFromComputedStyleInternal(
@@ -7997,7 +7956,7 @@
 const CSSValue* Widows::ParseSingleValue(CSSParserTokenRange& range,
                                          const CSSParserContext& context,
                                          const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumePositiveInteger(range, context);
+  return css_parsing_utils::ConsumePositiveInteger(range, context);
 }
 
 const CSSValue* Widows::CSSValueFromComputedStyleInternal(
@@ -8013,7 +7972,7 @@
                                         const CSSParserContext& context,
                                         const CSSParserLocalContext&) const {
   return css_parsing_utils::ConsumeWidthOrHeight(
-      range, context, css_property_parser_helpers::UnitlessQuirk::kAllow);
+      range, context, css_parsing_utils::UnitlessQuirk::kAllow);
 }
 
 bool Width::IsLayoutDependent(const ComputedStyle* style,
@@ -8039,7 +7998,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
+    return css_parsing_utils::ConsumeIdent(range);
 
   CSSValueList* values = CSSValueList::CreateCommaSeparated();
   // Every comma-separated list of identifiers is a valid will-change value,
@@ -8075,7 +8034,7 @@
           return nullptr;
         case CSSValueID::kContents:
         case CSSValueID::kScrollPosition:
-          values->Append(*css_property_parser_helpers::ConsumeIdent(range));
+          values->Append(*css_parsing_utils::ConsumeIdent(range));
           break;
         default:
           range.ConsumeIncludingWhitespace();
@@ -8085,7 +8044,7 @@
 
     if (range.AtEnd())
       break;
-    if (!css_property_parser_helpers::ConsumeCommaIncludingWhitespace(range))
+    if (!css_parsing_utils::ConsumeCommaIncludingWhitespace(range))
       return nullptr;
   }
 
@@ -8200,8 +8159,8 @@
 const CSSValue* X::ParseSingleValue(CSSParserTokenRange& range,
                                     const CSSParserContext& context,
                                     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeSVGGeometryPropertyLength(
-      range, context, kValueRangeAll);
+  return css_parsing_utils::ConsumeSVGGeometryPropertyLength(range, context,
+                                                             kValueRangeAll);
 }
 
 const CSSValue* X::CSSValueFromComputedStyleInternal(
@@ -8216,8 +8175,8 @@
 const CSSValue* Y::ParseSingleValue(CSSParserTokenRange& range,
                                     const CSSParserContext& context,
                                     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeSVGGeometryPropertyLength(
-      range, context, kValueRangeAll);
+  return css_parsing_utils::ConsumeSVGGeometryPropertyLength(range, context,
+                                                             kValueRangeAll);
 }
 
 const CSSValue* Y::CSSValueFromComputedStyleInternal(
@@ -8233,8 +8192,8 @@
                                          const CSSParserContext& context,
                                          const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueID::kAuto)
-    return css_property_parser_helpers::ConsumeIdent(range);
-  return css_property_parser_helpers::ConsumeInteger(range, context);
+    return css_parsing_utils::ConsumeIdent(range);
+  return css_parsing_utils::ConsumeInteger(range, context);
 }
 
 const CSSValue* ZIndex::CSSValueFromComputedStyleInternal(
@@ -8254,16 +8213,16 @@
   const CSSParserToken& token = range.Peek();
   CSSValue* zoom = nullptr;
   if (token.GetType() == kIdentToken) {
-    CSSIdentifierValue* ident = css_property_parser_helpers::ConsumeIdent<
+    CSSIdentifierValue* ident = css_parsing_utils::ConsumeIdent<
         CSSValueID::kNormal, CSSValueID::kInternalResetEffective>(range);
     if (ident && isValueAllowedInMode(ident->GetValueID(), context.Mode()))
       zoom = ident;
   } else {
-    zoom = css_property_parser_helpers::ConsumePercent(range, context,
-                                                       kValueRangeNonNegative);
+    zoom = css_parsing_utils::ConsumePercent(range, context,
+                                             kValueRangeNonNegative);
     if (!zoom) {
-      zoom = css_property_parser_helpers::ConsumeNumber(range, context,
-                                                        kValueRangeNonNegative);
+      zoom = css_parsing_utils::ConsumeNumber(range, context,
+                                              kValueRangeNonNegative);
     }
   }
   if (zoom) {
@@ -8310,8 +8269,8 @@
     CSSParserTokenRange& range,
     const CSSParserContext&,
     const CSSParserLocalContext&) const {
-  return css_property_parser_helpers::ConsumeIdent<CSSValueID::kFabricated,
-                                                   CSSValueID::kNone>(range);
+  return css_parsing_utils::ConsumeIdent<CSSValueID::kFabricated,
+                                         CSSValueID::kNone>(range);
 }
 
 }  // namespace css_longhand
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
index 657fd78d..b2e7e23 100644
--- a/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
@@ -14,7 +14,6 @@
 #include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_fast_paths.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_local_context.h"
-#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
 #include "third_party/blink/renderer/core/css/parser/font_variant_east_asian_parser.h"
 #include "third_party/blink/renderer/core/css/parser/font_variant_ligatures_parser.h"
 #include "third_party/blink/renderer/core/css/parser/font_variant_numeric_parser.h"
@@ -43,17 +42,16 @@
                                 bool use_legacy_parsing) {
   switch (property) {
     case CSSPropertyID::kAnimationDelay:
-      return css_property_parser_helpers::ConsumeTime(range, context,
-                                                      kValueRangeAll);
+      return css_parsing_utils::ConsumeTime(range, context, kValueRangeAll);
     case CSSPropertyID::kAnimationDirection:
-      return css_property_parser_helpers::ConsumeIdent<
+      return css_parsing_utils::ConsumeIdent<
           CSSValueID::kNormal, CSSValueID::kAlternate, CSSValueID::kReverse,
           CSSValueID::kAlternateReverse>(range);
     case CSSPropertyID::kAnimationDuration:
-      return css_property_parser_helpers::ConsumeTime(range, context,
-                                                      kValueRangeNonNegative);
+      return css_parsing_utils::ConsumeTime(range, context,
+                                            kValueRangeNonNegative);
     case CSSPropertyID::kAnimationFillMode:
-      return css_property_parser_helpers::ConsumeIdent<
+      return css_parsing_utils::ConsumeIdent<
           CSSValueID::kNone, CSSValueID::kForwards, CSSValueID::kBackwards,
           CSSValueID::kBoth>(range);
     case CSSPropertyID::kAnimationIterationCount:
@@ -62,9 +60,8 @@
       return css_parsing_utils::ConsumeAnimationName(range, context,
                                                      use_legacy_parsing);
     case CSSPropertyID::kAnimationPlayState:
-      return css_property_parser_helpers::ConsumeIdent<CSSValueID::kRunning,
-                                                       CSSValueID::kPaused>(
-          range);
+      return css_parsing_utils::ConsumeIdent<CSSValueID::kRunning,
+                                             CSSValueID::kPaused>(range);
     case CSSPropertyID::kAnimationTimingFunction:
       return css_parsing_utils::ConsumeAnimationTimingFunction(range, context);
     default:
@@ -93,10 +90,9 @@
   }
 
   for (unsigned i = 0; i < longhand_count; ++i) {
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         shorthand.properties()[i]->PropertyID(), shorthand.id(), *longhands[i],
-        important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+        important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
         properties);
   }
   return range.AtEnd();
@@ -187,21 +183,19 @@
   CSSValue* result_y = nullptr;
 
   if (!css_parsing_utils::ConsumeBackgroundPosition(
-          range, context, css_property_parser_helpers::UnitlessQuirk::kAllow,
-          result_x, result_y) ||
+          range, context, css_parsing_utils::UnitlessQuirk::kAllow, result_x,
+          result_y) ||
       !range.AtEnd())
     return false;
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBackgroundPositionX, CSSPropertyID::kBackgroundPosition,
-      *result_x, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      *result_x, important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBackgroundPositionY, CSSPropertyID::kBackgroundPosition,
-      *result_y, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      *result_y, important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
   return true;
 }
@@ -229,17 +223,17 @@
       !range.AtEnd())
     return false;
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBackgroundRepeatX, CSSPropertyID::kBackgroundRepeat,
       *result_x, important,
-      implicit ? css_property_parser_helpers::IsImplicitProperty::kImplicit
-               : css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      implicit ? css_parsing_utils::IsImplicitProperty::kImplicit
+               : css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBackgroundRepeatY, CSSPropertyID::kBackgroundRepeat,
       *result_y, important,
-      implicit ? css_property_parser_helpers::IsImplicitProperty::kImplicit
-               : css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      implicit ? css_parsing_utils::IsImplicitProperty::kImplicit
+               : css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
 
   return true;
@@ -260,7 +254,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       borderBlockColorShorthand(), important, context, range, properties);
 }
 
@@ -283,16 +277,16 @@
   const CSSValue* style = nullptr;
   const CSSValue* color = nullptr;
 
-  if (!css_property_parser_helpers::ConsumeBorderShorthand(
-          range, context, width, style, color)) {
+  if (!css_parsing_utils::ConsumeBorderShorthand(range, context, width, style,
+                                                 color)) {
     return false;
   };
 
-  css_property_parser_helpers::AddExpandedPropertyForValue(
+  css_parsing_utils::AddExpandedPropertyForValue(
       CSSPropertyID::kBorderBlockWidth, *width, important, properties);
-  css_property_parser_helpers::AddExpandedPropertyForValue(
+  css_parsing_utils::AddExpandedPropertyForValue(
       CSSPropertyID::kBorderBlockStyle, *style, important, properties);
-  css_property_parser_helpers::AddExpandedPropertyForValue(
+  css_parsing_utils::AddExpandedPropertyForValue(
       CSSPropertyID::kBorderBlockColor, *color, important, properties);
 
   return range.AtEnd();
@@ -321,7 +315,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandGreedilyViaLonghands(
+  return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
       borderBlockEndShorthand(), important, context, range, properties);
 }
 
@@ -331,7 +325,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandGreedilyViaLonghands(
+  return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
       borderBlockStartShorthand(), important, context, range, properties);
 }
 
@@ -341,7 +335,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       borderBlockStyleShorthand(), important, context, range, properties);
 }
 
@@ -360,7 +354,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       borderBlockWidthShorthand(), important, context, range, properties);
 }
 
@@ -379,7 +373,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandGreedilyViaLonghands(
+  return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
       borderBottomShorthand(), important, context, range, properties);
 }
 
@@ -398,7 +392,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia4Longhands(
+  return css_parsing_utils::ConsumeShorthandVia4Longhands(
       borderColorShorthand(), important, context, range, properties);
 }
 
@@ -421,20 +415,20 @@
   const CSSValue* style = nullptr;
   const CSSValue* color = nullptr;
 
-  if (!css_property_parser_helpers::ConsumeBorderShorthand(
-          range, context, width, style, color)) {
+  if (!css_parsing_utils::ConsumeBorderShorthand(range, context, width, style,
+                                                 color)) {
     return false;
   };
 
-  css_property_parser_helpers::AddExpandedPropertyForValue(
-      CSSPropertyID::kBorderWidth, *width, important, properties);
-  css_property_parser_helpers::AddExpandedPropertyForValue(
-      CSSPropertyID::kBorderStyle, *style, important, properties);
-  css_property_parser_helpers::AddExpandedPropertyForValue(
-      CSSPropertyID::kBorderColor, *color, important, properties);
-  css_property_parser_helpers::AddExpandedPropertyForValue(
-      CSSPropertyID::kBorderImage, *CSSInitialValue::Create(), important,
-      properties);
+  css_parsing_utils::AddExpandedPropertyForValue(CSSPropertyID::kBorderWidth,
+                                                 *width, important, properties);
+  css_parsing_utils::AddExpandedPropertyForValue(CSSPropertyID::kBorderStyle,
+                                                 *style, important, properties);
+  css_parsing_utils::AddExpandedPropertyForValue(CSSPropertyID::kBorderColor,
+                                                 *color, important, properties);
+  css_parsing_utils::AddExpandedPropertyForValue(CSSPropertyID::kBorderImage,
+                                                 *CSSInitialValue::Create(),
+                                                 important, properties);
 
   return range.AtEnd();
 }
@@ -477,38 +471,38 @@
     return false;
   }
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBorderImageSource, CSSPropertyID::kBorderImage,
       source
           ? *source
           : *To<Longhand>(&GetCSSPropertyBorderImageSource())->InitialValue(),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBorderImageSlice, CSSPropertyID::kBorderImage,
       slice ? *slice
             : *To<Longhand>(&GetCSSPropertyBorderImageSlice())->InitialValue(),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBorderImageWidth, CSSPropertyID::kBorderImage,
       width ? *width
             : *To<Longhand>(&GetCSSPropertyBorderImageWidth())->InitialValue(),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBorderImageOutset, CSSPropertyID::kBorderImage,
       outset
           ? *outset
           : *To<Longhand>(&GetCSSPropertyBorderImageOutset())->InitialValue(),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBorderImageRepeat, CSSPropertyID::kBorderImage,
       repeat
           ? *repeat
           : *To<Longhand>(&GetCSSPropertyBorderImageRepeat())->InitialValue(),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
 
   return true;
@@ -529,7 +523,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       borderInlineColorShorthand(), important, context, range, properties);
 }
 
@@ -552,16 +546,16 @@
   const CSSValue* style = nullptr;
   const CSSValue* color = nullptr;
 
-  if (!css_property_parser_helpers::ConsumeBorderShorthand(
-          range, context, width, style, color)) {
+  if (!css_parsing_utils::ConsumeBorderShorthand(range, context, width, style,
+                                                 color)) {
     return false;
   };
 
-  css_property_parser_helpers::AddExpandedPropertyForValue(
+  css_parsing_utils::AddExpandedPropertyForValue(
       CSSPropertyID::kBorderInlineWidth, *width, important, properties);
-  css_property_parser_helpers::AddExpandedPropertyForValue(
+  css_parsing_utils::AddExpandedPropertyForValue(
       CSSPropertyID::kBorderInlineStyle, *style, important, properties);
-  css_property_parser_helpers::AddExpandedPropertyForValue(
+  css_parsing_utils::AddExpandedPropertyForValue(
       CSSPropertyID::kBorderInlineColor, *color, important, properties);
 
   return range.AtEnd();
@@ -590,7 +584,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandGreedilyViaLonghands(
+  return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
       borderInlineEndShorthand(), important, context, range, properties);
 }
 
@@ -600,7 +594,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandGreedilyViaLonghands(
+  return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
       borderInlineStartShorthand(), important, context, range, properties);
 }
 
@@ -610,7 +604,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       borderInlineStyleShorthand(), important, context, range, properties);
 }
 
@@ -629,7 +623,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       borderInlineWidthShorthand(), important, context, range, properties);
 }
 
@@ -648,7 +642,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandGreedilyViaLonghands(
+  return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
       borderLeftShorthand(), important, context, range, properties);
 }
 
@@ -675,33 +669,33 @@
                                        local_context.UseAliasParsing()))
     return false;
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBorderTopLeftRadius, CSSPropertyID::kBorderRadius,
       *MakeGarbageCollected<CSSValuePair>(horizontal_radii[0],
                                           vertical_radii[0],
                                           CSSValuePair::kDropIdenticalValues),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBorderTopRightRadius, CSSPropertyID::kBorderRadius,
       *MakeGarbageCollected<CSSValuePair>(horizontal_radii[1],
                                           vertical_radii[1],
                                           CSSValuePair::kDropIdenticalValues),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBorderBottomRightRadius, CSSPropertyID::kBorderRadius,
       *MakeGarbageCollected<CSSValuePair>(horizontal_radii[2],
                                           vertical_radii[2],
                                           CSSValuePair::kDropIdenticalValues),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBorderBottomLeftRadius, CSSPropertyID::kBorderRadius,
       *MakeGarbageCollected<CSSValuePair>(horizontal_radii[3],
                                           vertical_radii[3],
                                           CSSValuePair::kDropIdenticalValues),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
   return true;
 }
@@ -720,7 +714,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandGreedilyViaLonghands(
+  return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
       borderRightShorthand(), important, context, range, properties);
 }
 
@@ -741,27 +735,24 @@
     HeapVector<CSSPropertyValue, 256>& properties) const {
   CSSValue* horizontal_spacing =
       ConsumeLength(range, context, kValueRangeNonNegative,
-                    css_property_parser_helpers::UnitlessQuirk::kAllow);
+                    css_parsing_utils::UnitlessQuirk::kAllow);
   if (!horizontal_spacing)
     return false;
   CSSValue* vertical_spacing = horizontal_spacing;
   if (!range.AtEnd()) {
-    vertical_spacing =
-        ConsumeLength(range, context, kValueRangeNonNegative,
-                      css_property_parser_helpers::UnitlessQuirk::kAllow);
+    vertical_spacing = ConsumeLength(range, context, kValueRangeNonNegative,
+                                     css_parsing_utils::UnitlessQuirk::kAllow);
   }
   if (!vertical_spacing || !range.AtEnd())
     return false;
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kWebkitBorderHorizontalSpacing,
       CSSPropertyID::kBorderSpacing, *horizontal_spacing, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kWebkitBorderVerticalSpacing,
       CSSPropertyID::kBorderSpacing, *vertical_spacing, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   return true;
 }
 
@@ -782,7 +773,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia4Longhands(
+  return css_parsing_utils::ConsumeShorthandVia4Longhands(
       borderStyleShorthand(), important, context, range, properties);
 }
 
@@ -801,7 +792,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandGreedilyViaLonghands(
+  return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
       borderTopShorthand(), important, context, range, properties);
 }
 
@@ -820,7 +811,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia4Longhands(
+  return css_parsing_utils::ConsumeShorthandVia4Longhands(
       borderWidthShorthand(), important, context, range, properties);
 }
 
@@ -839,7 +830,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandGreedilyViaLonghands(
+  return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
       columnRuleShorthand(), important, context, range, properties);
 }
 
@@ -871,13 +862,13 @@
     column_width = CSSIdentifierValue::Create(CSSValueID::kAuto);
   if (!column_count)
     column_count = CSSIdentifierValue::Create(CSSValueID::kAuto);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kColumnWidth, CSSPropertyID::kInvalid, *column_width,
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kColumnCount, CSSPropertyID::kInvalid, *column_count,
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
   return true;
 }
@@ -910,7 +901,7 @@
     unsigned index = 0;
     while (!range.AtEnd() && index++ < 3) {
       double num;
-      if (css_property_parser_helpers::ConsumeNumberRaw(range, context, num)) {
+      if (css_parsing_utils::ConsumeNumberRaw(range, context, num)) {
         if (num < 0)
           return false;
         if (flex_grow == kUnsetValue) {
@@ -928,9 +919,9 @@
         }
       } else if (!flex_basis) {
         if (range.Peek().Id() == CSSValueID::kAuto)
-          flex_basis = css_property_parser_helpers::ConsumeIdent(range);
+          flex_basis = css_parsing_utils::ConsumeIdent(range);
         if (!flex_basis) {
-          flex_basis = css_property_parser_helpers::ConsumeLengthOrPercent(
+          flex_basis = css_parsing_utils::ConsumeLengthOrPercent(
               range, context, kValueRangeNonNegative);
         }
         if (index == 2 && !range.AtEnd())
@@ -951,23 +942,22 @@
 
   if (!range.AtEnd())
     return false;
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFlexGrow, CSSPropertyID::kFlex,
       *CSSNumericLiteralValue::Create(clampTo<float>(flex_grow),
                                       CSSPrimitiveValue::UnitType::kNumber),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFlexShrink, CSSPropertyID::kFlex,
       *CSSNumericLiteralValue::Create(clampTo<float>(flex_shrink),
                                       CSSPrimitiveValue::UnitType::kNumber),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFlexBasis, CSSPropertyID::kFlex, *flex_basis, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
 
   return true;
 }
@@ -987,7 +977,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandGreedilyViaLonghands(
+  return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
       flexFlowShorthand(), important, context, range, properties);
 }
 
@@ -1017,63 +1007,57 @@
   LayoutTheme::GetTheme().SystemFont(system_font_id, font_style, font_weight,
                                      font_size, font_family);
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontStyle, CSSPropertyID::kFont,
       *CSSIdentifierValue::Create(font_style == ItalicSlopeValue()
                                       ? CSSValueID::kItalic
                                       : CSSValueID::kNormal),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontWeight, CSSPropertyID::kFont,
       *CSSNumericLiteralValue::Create(font_weight,
                                       CSSPrimitiveValue::UnitType::kNumber),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontSize, CSSPropertyID::kFont,
       *CSSNumericLiteralValue::Create(font_size,
                                       CSSPrimitiveValue::UnitType::kPixels),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
 
   CSSValueList* font_family_list = CSSValueList::CreateCommaSeparated();
   font_family_list->Append(*CSSFontFamilyValue::Create(font_family));
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontFamily, CSSPropertyID::kFont, *font_family_list,
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontStretch, CSSPropertyID::kFont,
       *CSSIdentifierValue::Create(CSSValueID::kNormal), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontVariantCaps, CSSPropertyID::kFont,
       *CSSIdentifierValue::Create(CSSValueID::kNormal), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontVariantLigatures, CSSPropertyID::kFont,
       *CSSIdentifierValue::Create(CSSValueID::kNormal), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontVariantNumeric, CSSPropertyID::kFont,
       *CSSIdentifierValue::Create(CSSValueID::kNormal), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontVariantEastAsian, CSSPropertyID::kFont,
       *CSSIdentifierValue::Create(CSSValueID::kNormal), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kLineHeight, CSSPropertyID::kFont,
       *CSSIdentifierValue::Create(CSSValueID::kNormal), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   return true;
 }
 
@@ -1091,7 +1075,7 @@
   for (int i = 0; i < kNumReorderableFontProperties && !range.AtEnd(); ++i) {
     CSSValueID id = range.Peek().Id();
     if (id == CSSValueID::kNormal) {
-      css_property_parser_helpers::ConsumeIdent(range);
+      css_parsing_utils::ConsumeIdent(range);
       continue;
     }
     if (!font_style &&
@@ -1130,45 +1114,42 @@
   if (range.AtEnd())
     return false;
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontStyle, CSSPropertyID::kFont,
       font_style ? *font_style
                  : *CSSIdentifierValue::Create(CSSValueID::kNormal),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontVariantCaps, CSSPropertyID::kFont,
       font_variant_caps ? *font_variant_caps
                         : *CSSIdentifierValue::Create(CSSValueID::kNormal),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontVariantLigatures, CSSPropertyID::kFont,
       *CSSIdentifierValue::Create(CSSValueID::kNormal), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontVariantNumeric, CSSPropertyID::kFont,
       *CSSIdentifierValue::Create(CSSValueID::kNormal), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontVariantEastAsian, CSSPropertyID::kFont,
       *CSSIdentifierValue::Create(CSSValueID::kNormal), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontWeight, CSSPropertyID::kFont,
       font_weight ? *font_weight
                   : *CSSIdentifierValue::Create(CSSValueID::kNormal),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontStretch, CSSPropertyID::kFont,
       font_stretch ? *font_stretch
                    : *CSSIdentifierValue::Create(CSSValueID::kNormal),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
 
   // Now a font size _must_ come.
@@ -1176,27 +1157,24 @@
   if (!font_size || range.AtEnd())
     return false;
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontSize, CSSPropertyID::kFont, *font_size, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
 
-  if (css_property_parser_helpers::ConsumeSlashIncludingWhitespace(range)) {
+  if (css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
     CSSValue* line_height =
         css_parsing_utils::ConsumeLineHeight(range, context);
     if (!line_height)
       return false;
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kLineHeight, CSSPropertyID::kFont, *line_height,
-        important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+        important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
         properties);
   } else {
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kLineHeight, CSSPropertyID::kFont,
         *CSSIdentifierValue::Create(CSSValueID::kNormal), important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   }
 
   // Font family must come now.
@@ -1204,9 +1182,9 @@
   if (!parsed_family_value)
     return false;
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontFamily, CSSPropertyID::kFont, *parsed_family_value,
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
 
   // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires
@@ -1244,29 +1222,24 @@
     const CSSParserContext&,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  if (css_property_parser_helpers::IdentMatches<CSSValueID::kNormal,
-                                                CSSValueID::kNone>(
+  if (css_parsing_utils::IdentMatches<CSSValueID::kNormal, CSSValueID::kNone>(
           range.Peek().Id())) {
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kFontVariantLigatures, CSSPropertyID::kFontVariant,
-        *css_property_parser_helpers::ConsumeIdent(range), important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
-    css_property_parser_helpers::AddProperty(
+        *css_parsing_utils::ConsumeIdent(range), important,
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kFontVariantCaps, CSSPropertyID::kFontVariant,
         *CSSIdentifierValue::Create(CSSValueID::kNormal), important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
-    css_property_parser_helpers::AddProperty(
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kFontVariantNumeric, CSSPropertyID::kFontVariant,
         *CSSIdentifierValue::Create(CSSValueID::kNormal), important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
-    css_property_parser_helpers::AddProperty(
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kFontVariantEastAsian, CSSPropertyID::kFontVariant,
         *CSSIdentifierValue::Create(CSSValueID::kNormal), important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
     return range.AtEnd();
   }
 
@@ -1308,33 +1281,30 @@
         // Only one caps value permitted in font-variant grammar.
         if (caps_value)
           return false;
-        caps_value = css_property_parser_helpers::ConsumeIdent(range);
+        caps_value = css_parsing_utils::ConsumeIdent(range);
         break;
       default:
         return false;
     }
   } while (!range.AtEnd());
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontVariantLigatures, CSSPropertyID::kFontVariant,
       *ligatures_parser.FinalizeValue(), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontVariantNumeric, CSSPropertyID::kFontVariant,
       *numeric_parser.FinalizeValue(), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontVariantEastAsian, CSSPropertyID::kFontVariant,
       *east_asian_parser.FinalizeValue(), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kFontVariantCaps, CSSPropertyID::kFontVariant,
       caps_value ? *caps_value
                  : *CSSIdentifierValue::Create(CSSValueID::kNormal),
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
   return true;
 }
@@ -1360,14 +1330,12 @@
     return false;
   if (!column_gap)
     column_gap = row_gap;
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kRowGap, CSSPropertyID::kGap, *row_gap, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kColumnGap, CSSPropertyID::kGap, *column_gap, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   return true;
 }
 
@@ -1395,15 +1363,15 @@
   CSSValue* column_start_value = nullptr;
   CSSValue* row_end_value = nullptr;
   CSSValue* column_end_value = nullptr;
-  if (css_property_parser_helpers::ConsumeSlashIncludingWhitespace(range)) {
+  if (css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
     column_start_value = css_parsing_utils::ConsumeGridLine(range, context);
     if (!column_start_value)
       return false;
-    if (css_property_parser_helpers::ConsumeSlashIncludingWhitespace(range)) {
+    if (css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
       row_end_value = css_parsing_utils::ConsumeGridLine(range, context);
       if (!row_end_value)
         return false;
-      if (css_property_parser_helpers::ConsumeSlashIncludingWhitespace(range)) {
+      if (css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
         column_end_value = css_parsing_utils::ConsumeGridLine(range, context);
         if (!column_end_value)
           return false;
@@ -1428,24 +1396,22 @@
                            : CSSIdentifierValue::Create(CSSValueID::kAuto);
   }
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kGridRowStart, CSSPropertyID::kGridArea, *row_start_value,
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kGridColumnStart, CSSPropertyID::kGridArea,
       *column_start_value, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kGridRowEnd, CSSPropertyID::kGridArea, *row_end_value,
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kGridColumnEnd, CSSPropertyID::kGridArea,
       *column_end_value, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   return true;
 }
 
@@ -1475,16 +1441,14 @@
     return false;
   }
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       shorthand.properties()[0]->PropertyID(), CSSPropertyID::kGridColumn,
       *start_value, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       shorthand.properties()[1]->PropertyID(), CSSPropertyID::kGridColumn,
       *end_value, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
 
   return true;
 }
@@ -1508,9 +1472,9 @@
   if (!gap_length || !range.AtEnd())
     return false;
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kColumnGap, CSSPropertyID::kGridColumnGap, *gap_length,
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
   return true;
 }
@@ -1530,17 +1494,15 @@
                                       const CSSValue& flow_direction) {
   // [ auto-flow && dense? ]
   CSSValue* dense_algorithm = nullptr;
-  if ((css_property_parser_helpers::ConsumeIdent<CSSValueID::kAutoFlow>(
-          range))) {
+  if ((css_parsing_utils::ConsumeIdent<CSSValueID::kAutoFlow>(range))) {
     dense_algorithm =
-        css_property_parser_helpers::ConsumeIdent<CSSValueID::kDense>(range);
+        css_parsing_utils::ConsumeIdent<CSSValueID::kDense>(range);
   } else {
     dense_algorithm =
-        css_property_parser_helpers::ConsumeIdent<CSSValueID::kDense>(range);
+        css_parsing_utils::ConsumeIdent<CSSValueID::kDense>(range);
     if (!dense_algorithm)
       return nullptr;
-    if (!css_property_parser_helpers::ConsumeIdent<CSSValueID::kAutoFlow>(
-            range))
+    if (!css_parsing_utils::ConsumeIdent<CSSValueID::kAutoFlow>(range))
       return nullptr;
   }
   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
@@ -1572,40 +1534,34 @@
     DCHECK(template_columns);
     DCHECK(template_areas);
 
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kGridTemplateRows, CSSPropertyID::kGrid, *template_rows,
-        important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+        important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
         properties);
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kGridTemplateColumns, CSSPropertyID::kGrid,
         *template_columns, important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
-    css_property_parser_helpers::AddProperty(
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kGridTemplateAreas, CSSPropertyID::kGrid,
         *template_areas, important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
 
     // It can only be specified the explicit or the implicit grid properties in
     // a single grid declaration. The sub-properties not specified are set to
     // their initial value, as normal for shorthands.
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kGridAutoFlow, CSSPropertyID::kGrid,
         *CSSInitialValue::Create(), important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
-    css_property_parser_helpers::AddProperty(
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kGridAutoColumns, CSSPropertyID::kGrid,
         *CSSInitialValue::Create(), important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
-    css_property_parser_helpers::AddProperty(
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kGridAutoRows, CSSPropertyID::kGrid,
         *CSSInitialValue::Create(), important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
     return true;
   }
 
@@ -1617,22 +1573,22 @@
   template_rows = nullptr;
   template_columns = nullptr;
 
-  if (css_property_parser_helpers::IdentMatches<CSSValueID::kDense,
-                                                CSSValueID::kAutoFlow>(
+  if (css_parsing_utils::IdentMatches<CSSValueID::kDense,
+                                      CSSValueID::kAutoFlow>(
           range.Peek().Id())) {
     // 2- [ auto-flow && dense? ] <grid-auto-rows>? / <grid-template-columns>
     grid_auto_flow = ConsumeImplicitAutoFlow(
         range, *CSSIdentifierValue::Create(CSSValueID::kRow));
     if (!grid_auto_flow)
       return false;
-    if (css_property_parser_helpers::ConsumeSlashIncludingWhitespace(range)) {
+    if (css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
       auto_rows_value = CSSInitialValue::Create();
     } else {
       auto_rows_value = css_parsing_utils::ConsumeGridTrackList(
           range, context, css_parsing_utils::TrackListType::kGridAuto);
       if (!auto_rows_value)
         return false;
-      if (!css_property_parser_helpers::ConsumeSlashIncludingWhitespace(range))
+      if (!css_parsing_utils::ConsumeSlashIncludingWhitespace(range))
         return false;
     }
     if (!(template_columns =
@@ -1647,7 +1603,7 @@
         css_parsing_utils::ConsumeGridTemplatesRowsOrColumns(range, context);
     if (!template_rows)
       return false;
-    if (!css_property_parser_helpers::ConsumeSlashIncludingWhitespace(range))
+    if (!css_parsing_utils::ConsumeSlashIncludingWhitespace(range))
       return false;
     grid_auto_flow = ConsumeImplicitAutoFlow(
         range, *CSSIdentifierValue::Create(CSSValueID::kColumn));
@@ -1671,32 +1627,29 @@
   // It can only be specified the explicit or the implicit grid properties in a
   // single grid declaration. The sub-properties not specified are set to their
   // initial value, as normal for shorthands.
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kGridTemplateColumns, CSSPropertyID::kGrid,
       *template_columns, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kGridTemplateRows, CSSPropertyID::kGrid, *template_rows,
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kGridTemplateAreas, CSSPropertyID::kGrid,
       *CSSInitialValue::Create(), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kGridAutoFlow, CSSPropertyID::kGrid, *grid_auto_flow,
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kGridAutoColumns, CSSPropertyID::kGrid,
       *auto_columns_value, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kGridAutoRows, CSSPropertyID::kGrid, *auto_rows_value,
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
   return true;
 }
@@ -1728,14 +1681,12 @@
     return false;
   if (!column_gap)
     column_gap = row_gap;
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kRowGap, CSSPropertyID::kGap, *row_gap, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kColumnGap, CSSPropertyID::kGap, *column_gap, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   return true;
 }
 
@@ -1765,16 +1716,14 @@
     return false;
   }
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       shorthand.properties()[0]->PropertyID(), CSSPropertyID::kGridRow,
       *start_value, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       shorthand.properties()[1]->PropertyID(), CSSPropertyID::kGridRow,
       *end_value, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
 
   return true;
 }
@@ -1798,9 +1747,9 @@
   if (!gap_length || !range.AtEnd())
     return false;
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kRowGap, CSSPropertyID::kGridRowGap, *gap_length,
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
   return true;
 }
@@ -1832,21 +1781,18 @@
   DCHECK(template_columns);
   DCHECK(template_areas);
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kGridTemplateRows, CSSPropertyID::kGridTemplate,
       *template_rows, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kGridTemplateColumns, CSSPropertyID::kGridTemplate,
       *template_columns, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kGridTemplateAreas, CSSPropertyID::kGridTemplate,
       *template_areas, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
 
   return true;
 }
@@ -1871,7 +1817,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       insetBlockShorthand(), important, context, range, properties);
 }
 
@@ -1890,7 +1836,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia4Longhands(
+  return css_parsing_utils::ConsumeShorthandVia4Longhands(
       insetShorthand(), important, context, range, properties);
 }
 
@@ -1909,7 +1855,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       insetInlineShorthand(), important, context, range, properties);
 }
 
@@ -1934,27 +1880,26 @@
   const CSSValue* list_style_type = nullptr;
   do {
     if (!none) {
-      none =
-          css_property_parser_helpers::ConsumeIdent<CSSValueID::kNone>(range);
+      none = css_parsing_utils::ConsumeIdent<CSSValueID::kNone>(range);
       if (none)
         continue;
     }
     if (!list_style_position) {
-      list_style_position = css_property_parser_helpers::ParseLonghand(
+      list_style_position = css_parsing_utils::ParseLonghand(
           CSSPropertyID::kListStylePosition, CSSPropertyID::kListStyle, context,
           range);
       if (list_style_position)
         continue;
     }
     if (!list_style_image) {
-      list_style_image = css_property_parser_helpers::ParseLonghand(
+      list_style_image = css_parsing_utils::ParseLonghand(
           CSSPropertyID::kListStyleImage, CSSPropertyID::kListStyle, context,
           range);
       if (list_style_image)
         continue;
     }
     if (!list_style_type) {
-      list_style_type = css_property_parser_helpers::ParseLonghand(
+      list_style_type = css_parsing_utils::ParseLonghand(
           CSSPropertyID::kListStyleType, CSSPropertyID::kListStyle, context,
           range);
       if (list_style_type)
@@ -1974,36 +1919,36 @@
   if (list_style_position) {
     AddProperty(CSSPropertyID::kListStylePosition, CSSPropertyID::kListStyle,
                 *list_style_position, important,
-                css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+                css_parsing_utils::IsImplicitProperty::kNotImplicit,
                 properties);
   } else {
     AddProperty(CSSPropertyID::kListStylePosition, CSSPropertyID::kListStyle,
                 *CSSInitialValue::Create(), important,
-                css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+                css_parsing_utils::IsImplicitProperty::kNotImplicit,
                 properties);
   }
 
   if (list_style_image) {
     AddProperty(CSSPropertyID::kListStyleImage, CSSPropertyID::kListStyle,
                 *list_style_image, important,
-                css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+                css_parsing_utils::IsImplicitProperty::kNotImplicit,
                 properties);
   } else {
     AddProperty(CSSPropertyID::kListStyleImage, CSSPropertyID::kListStyle,
                 *CSSInitialValue::Create(), important,
-                css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+                css_parsing_utils::IsImplicitProperty::kNotImplicit,
                 properties);
   }
 
   if (list_style_type) {
     AddProperty(CSSPropertyID::kListStyleType, CSSPropertyID::kListStyle,
                 *list_style_type, important,
-                css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+                css_parsing_utils::IsImplicitProperty::kNotImplicit,
                 properties);
   } else {
     AddProperty(CSSPropertyID::kListStyleType, CSSPropertyID::kListStyle,
                 *CSSInitialValue::Create(), important,
-                css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+                css_parsing_utils::IsImplicitProperty::kNotImplicit,
                 properties);
   }
 
@@ -2025,7 +1970,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       marginBlockShorthand(), important, context, range, properties);
 }
 
@@ -2044,7 +1989,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia4Longhands(
+  return css_parsing_utils::ConsumeShorthandVia4Longhands(
       marginShorthand(), important, context, range, properties);
 }
 
@@ -2071,7 +2016,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       marginInlineShorthand(), important, context, range, properties);
 }
 
@@ -2090,23 +2035,20 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  const CSSValue* marker = css_property_parser_helpers::ParseLonghand(
+  const CSSValue* marker = css_parsing_utils::ParseLonghand(
       CSSPropertyID::kMarkerStart, CSSPropertyID::kMarker, context, range);
   if (!marker || !range.AtEnd())
     return false;
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kMarkerStart, CSSPropertyID::kMarker, *marker, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kMarkerMid, CSSPropertyID::kMarker, *marker, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kMarkerEnd, CSSPropertyID::kMarker, *marker, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   return true;
 }
 
@@ -2144,16 +2086,16 @@
   const CSSValue* offset_distance = nullptr;
   const CSSValue* offset_rotate = nullptr;
   if (offset_path) {
-    offset_distance = css_property_parser_helpers::ConsumeLengthOrPercent(
-        range, context, kValueRangeAll);
+    offset_distance = css_parsing_utils::ConsumeLengthOrPercent(range, context,
+                                                                kValueRangeAll);
     offset_rotate = css_parsing_utils::ConsumeOffsetRotate(range, context);
     if (offset_rotate && !offset_distance) {
-      offset_distance = css_property_parser_helpers::ConsumeLengthOrPercent(
+      offset_distance = css_parsing_utils::ConsumeLengthOrPercent(
           range, context, kValueRangeAll);
     }
   }
   const CSSValue* offset_anchor = nullptr;
-  if (css_property_parser_helpers::ConsumeSlashIncludingWhitespace(range)) {
+  if (css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
     offset_anchor =
         To<Longhand>(GetCSSPropertyOffsetAnchor())
             .ParseSingleValue(range, context, CSSParserLocalContext());
@@ -2168,73 +2110,63 @@
     return false;
 
   if (offset_position) {
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kOffsetPosition, CSSPropertyID::kOffset,
         *offset_position, important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   } else if (RuntimeEnabledFeatures::CSSOffsetPositionAnchorEnabled()) {
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kOffsetPosition, CSSPropertyID::kOffset,
         *CSSInitialValue::Create(), important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   }
 
   if (offset_path) {
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kOffsetPath, CSSPropertyID::kOffset, *offset_path,
-        important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+        important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
         properties);
   } else {
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kOffsetPath, CSSPropertyID::kOffset,
         *CSSInitialValue::Create(), important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   }
 
   if (offset_distance) {
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kOffsetDistance, CSSPropertyID::kOffset,
         *offset_distance, important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   } else {
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kOffsetDistance, CSSPropertyID::kOffset,
         *CSSInitialValue::Create(), important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   }
 
   if (offset_rotate) {
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kOffsetRotate, CSSPropertyID::kOffset, *offset_rotate,
-        important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+        important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
         properties);
   } else {
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kOffsetRotate, CSSPropertyID::kOffset,
         *CSSInitialValue::Create(), important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   }
 
   if (offset_anchor) {
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kOffsetAnchor, CSSPropertyID::kOffset, *offset_anchor,
-        important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+        important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
         properties);
   } else if (RuntimeEnabledFeatures::CSSOffsetPositionAnchorEnabled()) {
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         CSSPropertyID::kOffsetAnchor, CSSPropertyID::kOffset,
         *CSSInitialValue::Create(), important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-        properties);
+        css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   }
 
   return true;
@@ -2255,7 +2187,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandGreedilyViaLonghands(
+  return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
       outlineShorthand(), important, context, range, properties);
 }
 
@@ -2274,7 +2206,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       overflowShorthand(), important, context, range, properties);
 }
 
@@ -2297,7 +2229,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       overscrollBehaviorShorthand(), important, context, range, properties);
 }
 
@@ -2320,7 +2252,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       paddingBlockShorthand(), important, context, range, properties);
 }
 
@@ -2339,7 +2271,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia4Longhands(
+  return css_parsing_utils::ConsumeShorthandVia4Longhands(
       paddingShorthand(), important, context, range, properties);
 }
 
@@ -2366,7 +2298,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       paddingInlineShorthand(), important, context, range, properties);
 }
 
@@ -2391,11 +2323,10 @@
   }
 
   DCHECK(IsValidCSSValueID(value));
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBreakAfter, CSSPropertyID::kPageBreakAfter,
       *CSSIdentifierValue::Create(value), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   return true;
 }
 
@@ -2419,11 +2350,10 @@
   }
 
   DCHECK(IsValidCSSValueID(value));
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBreakBefore, CSSPropertyID::kPageBreakBefore,
       *CSSIdentifierValue::Create(value), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   return true;
 }
 
@@ -2446,11 +2376,10 @@
     return false;
   }
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBreakInside, CSSPropertyID::kPageBreakInside,
       *CSSIdentifierValue::Create(value), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   return true;
 }
 
@@ -2500,16 +2429,14 @@
   DCHECK(align_content_value);
   DCHECK(justify_content_value);
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kAlignContent, CSSPropertyID::kPlaceContent,
       *align_content_value, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kJustifyContent, CSSPropertyID::kPlaceContent,
       *justify_content_value, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
 
   return true;
 }
@@ -2550,16 +2477,14 @@
   DCHECK(align_items_value);
   DCHECK(justify_items_value);
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kAlignItems, CSSPropertyID::kPlaceItems,
       *align_items_value, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kJustifyItems, CSSPropertyID::kPlaceItems,
       *justify_items_value, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
 
   return true;
 }
@@ -2600,15 +2525,14 @@
   DCHECK(align_self_value);
   DCHECK(justify_self_value);
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kAlignSelf, CSSPropertyID::kPlaceSelf, *align_self_value,
-      important, css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kJustifySelf, CSSPropertyID::kPlaceSelf,
       *justify_self_value, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
 
   return true;
 }
@@ -2628,7 +2552,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       scrollMarginBlockShorthand(), important, context, range, properties);
 }
 
@@ -2647,7 +2571,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia4Longhands(
+  return css_parsing_utils::ConsumeShorthandVia4Longhands(
       scrollMarginShorthand(), important, context, range, properties);
 }
 
@@ -2666,7 +2590,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       scrollMarginInlineShorthand(), important, context, range, properties);
 }
 
@@ -2685,7 +2609,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       scrollPaddingBlockShorthand(), important, context, range, properties);
 }
 
@@ -2704,7 +2628,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia4Longhands(
+  return css_parsing_utils::ConsumeShorthandVia4Longhands(
       scrollPaddingShorthand(), important, context, range, properties);
 }
 
@@ -2723,7 +2647,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandVia2Longhands(
+  return css_parsing_utils::ConsumeShorthandVia2Longhands(
       scrollPaddingInlineShorthand(), important, context, range, properties);
 }
 
@@ -2743,7 +2667,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandGreedilyViaLonghands(
+  return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
       textDecorationShorthand(), important, context, range, properties);
 }
 
@@ -2764,11 +2688,10 @@
                                  bool use_legacy_parsing) {
   switch (property) {
     case CSSPropertyID::kTransitionDelay:
-      return css_property_parser_helpers::ConsumeTime(range, context,
-                                                      kValueRangeAll);
+      return css_parsing_utils::ConsumeTime(range, context, kValueRangeAll);
     case CSSPropertyID::kTransitionDuration:
-      return css_property_parser_helpers::ConsumeTime(range, context,
-                                                      kValueRangeNonNegative);
+      return css_parsing_utils::ConsumeTime(range, context,
+                                            kValueRangeNonNegative);
     case CSSPropertyID::kTransitionProperty:
       return css_parsing_utils::ConsumeTransitionProperty(range, context);
     case CSSPropertyID::kTransitionTimingFunction:
@@ -2806,10 +2729,9 @@
   }
 
   for (unsigned i = 0; i < longhand_count; ++i) {
-    css_property_parser_helpers::AddProperty(
+    css_parsing_utils::AddProperty(
         shorthand.properties()[i]->PropertyID(), shorthand.id(), *longhands[i],
-        important,
-        css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+        important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
         properties);
   }
 
@@ -2867,11 +2789,10 @@
     return false;
   }
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBreakAfter, CSSPropertyID::kWebkitColumnBreakAfter,
       *CSSIdentifierValue::Create(value), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   return true;
 }
 
@@ -2895,11 +2816,10 @@
     return false;
   }
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBreakBefore, CSSPropertyID::kWebkitColumnBreakBefore,
       *CSSIdentifierValue::Create(value), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   return true;
 }
 
@@ -2923,11 +2843,10 @@
     return false;
   }
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kBreakInside, CSSPropertyID::kWebkitColumnBreakInside,
       *CSSIdentifierValue::Create(value), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
   return true;
 }
 
@@ -2958,36 +2877,31 @@
     return false;
   }
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kWebkitMaskBoxImageSource,
       CSSPropertyID::kWebkitMaskBoxImage,
       source ? *source : *CSSInitialValue::Create(), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kWebkitMaskBoxImageSlice,
       CSSPropertyID::kWebkitMaskBoxImage,
       slice ? *slice : *CSSInitialValue::Create(), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kWebkitMaskBoxImageWidth,
       CSSPropertyID::kWebkitMaskBoxImage,
       width ? *width : *CSSInitialValue::Create(), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kWebkitMaskBoxImageOutset,
       CSSPropertyID::kWebkitMaskBoxImage,
       outset ? *outset : *CSSInitialValue::Create(), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  css_property_parser_helpers::AddProperty(
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kWebkitMaskBoxImageRepeat,
       CSSPropertyID::kWebkitMaskBoxImage,
       repeat ? *repeat : *CSSInitialValue::Create(), important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
-      properties);
+      css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
 
   return true;
 }
@@ -3021,21 +2935,19 @@
   CSSValue* result_y = nullptr;
 
   if (!css_parsing_utils::ConsumeBackgroundPosition(
-          range, context, css_property_parser_helpers::UnitlessQuirk::kAllow,
-          result_x, result_y) ||
+          range, context, css_parsing_utils::UnitlessQuirk::kAllow, result_x,
+          result_y) ||
       !range.AtEnd())
     return false;
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kWebkitMaskPositionX, CSSPropertyID::kWebkitMaskPosition,
-      *result_x, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      *result_x, important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kWebkitMaskPositionY, CSSPropertyID::kWebkitMaskPosition,
-      *result_y, important,
-      css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      *result_y, important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
   return true;
 }
@@ -3063,17 +2975,17 @@
       !range.AtEnd())
     return false;
 
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kWebkitMaskRepeatX, CSSPropertyID::kWebkitMaskRepeat,
       *result_x, important,
-      implicit ? css_property_parser_helpers::IsImplicitProperty::kImplicit
-               : css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      implicit ? css_parsing_utils::IsImplicitProperty::kImplicit
+               : css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
-  css_property_parser_helpers::AddProperty(
+  css_parsing_utils::AddProperty(
       CSSPropertyID::kWebkitMaskRepeatY, CSSPropertyID::kWebkitMaskRepeat,
       *result_y, important,
-      implicit ? css_property_parser_helpers::IsImplicitProperty::kImplicit
-               : css_property_parser_helpers::IsImplicitProperty::kNotImplicit,
+      implicit ? css_parsing_utils::IsImplicitProperty::kImplicit
+               : css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
 
   return true;
@@ -3094,7 +3006,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandGreedilyViaLonghands(
+  return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
       webkitTextEmphasisShorthand(), important, context, range, properties);
 }
 
@@ -3104,7 +3016,7 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  return css_property_parser_helpers::ConsumeShorthandGreedilyViaLonghands(
+  return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
       webkitTextStrokeShorthand(), important, context, range, properties);
 }
 
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index bf1fd75..ca40ef64f 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -1084,13 +1084,14 @@
   return LayoutUnit::Clamp(ConvertComputedLength<float>(state, value));
 }
 
-GapLength StyleBuilderConverter::ConvertGapLength(StyleResolverState& state,
-                                                  const CSSValue& value) {
+base::Optional<Length> StyleBuilderConverter::ConvertGapLength(
+    const StyleResolverState& state,
+    const CSSValue& value) {
   auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
   if (identifier_value && identifier_value->GetValueID() == CSSValueID::kNormal)
-    return GapLength();
+    return base::nullopt;
 
-  return GapLength(ConvertLength(state, value));
+  return ConvertLength(state, value);
 }
 
 Length StyleBuilderConverter::ConvertLength(const StyleResolverState& state,
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.h b/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
index 0378463..21fcafa 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
@@ -152,7 +152,6 @@
   static StyleContentAlignmentData ConvertContentAlignmentData(
       StyleResolverState&,
       const CSSValue&);
-  static GapLength ConvertGapLength(StyleResolverState&, const CSSValue&);
   static GridAutoFlow ConvertGridAutoFlow(StyleResolverState&, const CSSValue&);
   static GridPosition ConvertGridPosition(StyleResolverState&, const CSSValue&);
   static GridTrackSize ConvertGridTrackSize(StyleResolverState&,
@@ -163,7 +162,8 @@
   static T ConvertLineWidth(StyleResolverState&, const CSSValue&);
   static float ConvertBorderWidth(StyleResolverState&, const CSSValue&);
   static LayoutUnit ConvertLayoutUnit(StyleResolverState&, const CSSValue&);
-  static GapLength ConvertGapLength(const StyleResolverState&, const CSSValue&);
+  static base::Optional<Length> ConvertGapLength(const StyleResolverState&,
+                                                 const CSSValue&);
   static Length ConvertLength(const StyleResolverState&, const CSSValue&);
   static UnzoomedLength ConvertUnzoomedLength(const StyleResolverState&,
                                               const CSSValue&);
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc
index d53ff96..902392d 100644
--- a/third_party/blink/renderer/core/css/style_engine.cc
+++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -2199,13 +2199,6 @@
     root_element->PropagateWritingModeAndDirectionFromBody();
 }
 
-void StyleEngine::PrintingStateChanged() {
-  ColorSchemeChanged();
-  MarkViewportStyleDirty();
-  MarkAllElementsForStyleRecalc(StyleChangeReasonForTracing::Create(
-      style_change_reason::kStyleSheetChange));
-}
-
 void StyleEngine::Trace(Visitor* visitor) const {
   visitor->Trace(document_);
   visitor->Trace(injected_user_style_sheets_);
diff --git a/third_party/blink/renderer/core/css/style_engine.h b/third_party/blink/renderer/core/css/style_engine.h
index 58d3683a..a93f7960 100644
--- a/third_party/blink/renderer/core/css/style_engine.h
+++ b/third_party/blink/renderer/core/css/style_engine.h
@@ -134,7 +134,6 @@
   void WatchedSelectorsChanged();
   void InitialStyleChanged();
   void ColorSchemeChanged();
-  void PrintingStateChanged();
   void InitialViewportChanged();
   void ViewportRulesChanged();
   void HtmlImportAddedOrRemoved();
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
index 4a986420..07c8dc9 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -150,19 +150,19 @@
     return context->needs_graphics_layer_collection_;
   }
 
-  mojom::blink::FindOptionsPtr FindOptions(bool find_next = false) {
+  mojom::blink::FindOptionsPtr FindOptions(bool new_session = true) {
     auto find_options = mojom::blink::FindOptions::New();
     find_options->run_synchronously_for_testing = true;
-    find_options->find_next = find_next;
+    find_options->new_session = new_session;
     find_options->forward = true;
     return find_options;
   }
 
   void Find(String search_text,
             DisplayLockTestFindInPageClient& client,
-            bool find_next = false) {
+            bool new_session = true) {
     client.Reset();
-    GetFindInPage()->Find(FAKE_FIND_ID, search_text, FindOptions(find_next));
+    GetFindInPage()->Find(FAKE_FIND_ID, search_text, FindOptions(new_session));
     test::RunPendingTasks();
   }
 
@@ -637,7 +637,7 @@
   CommitElement(*div_one);
 
   // Going forward from #one would go to #three.
-  Find(search_text, client, true /* find_next */);
+  Find(search_text, client, false /* new_session */);
   EXPECT_EQ(2, client.Count());
   EXPECT_EQ(2, client.ActiveIndex());
   EXPECT_EQ(text_rect(div_three), client.ActiveMatchRect());
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index d1cf336..d336892 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -1105,32 +1105,6 @@
   GetSecurityContext().SetSecureContextModeForTesting(mode);
 }
 
-bool Document::IsFeatureEnabled(mojom::blink::FeaturePolicyFeature feature,
-                                ReportOptions report_on_failure,
-                                const String& message) const {
-  return GetExecutionContext() && GetExecutionContext()->IsFeatureEnabled(
-                                      feature, report_on_failure, message);
-}
-
-bool Document::IsFeatureEnabled(mojom::blink::DocumentPolicyFeature feature,
-                                ReportOptions report_option,
-                                const String& message,
-                                const String& source_file) const {
-  return GetExecutionContext() &&
-         GetExecutionContext()->IsFeatureEnabled(feature, report_option,
-                                                 message, source_file);
-}
-
-bool Document::IsFeatureEnabled(mojom::blink::DocumentPolicyFeature feature,
-                                PolicyValue threshold_value,
-                                ReportOptions report_option,
-                                const String& message,
-                                const String& source_file) const {
-  return GetExecutionContext() &&
-         GetExecutionContext()->IsFeatureEnabled(
-             feature, threshold_value, report_option, message, source_file);
-}
-
 String Document::addressSpaceForBindings(ScriptState* script_state) const {
   // "public" is the lowest-privilege value.
   if (!script_state->ContextIsValid())
@@ -3525,14 +3499,24 @@
   printing_ = state;
   bool is_printing = Printing();
 
-  if ((was_printing != is_printing) && documentElement() && GetFrame() &&
-      !GetFrame()->IsMainFrame() && GetFrame()->Owner() &&
-      GetFrame()->Owner()->IsDisplayNone()) {
-    // In non-printing mode we do not generate style or layout objects for
-    // display:none iframes, yet we do when printing (see
-    // LayoutView::CanHaveChildren). Trigger a style recalc on the root element
-    // to create a layout tree for printing.
-    DisplayNoneChangedForFrame();
+  if (was_printing != is_printing) {
+    // We force the color-scheme to light for printing.
+    ColorSchemeChanged();
+    // StyleResolver::InitialStyleForElement uses different zoom for printing.
+    GetStyleEngine().MarkViewportStyleDirty();
+    // Separate UA sheet for printing.
+    GetStyleEngine().MarkAllElementsForStyleRecalc(
+        StyleChangeReasonForTracing::Create(
+            style_change_reason::kStyleSheetChange));
+
+    if (documentElement() && GetFrame() && !GetFrame()->IsMainFrame() &&
+        GetFrame()->Owner() && GetFrame()->Owner()->IsDisplayNone()) {
+      // In non-printing mode we do not generate style or layout objects for
+      // display:none iframes, yet we do when printing (see
+      // LayoutView::CanHaveChildren). Trigger a style recalc on the root
+      // element to create a layout tree for printing.
+      DisplayNoneChangedForFrame();
+    }
   }
 }
 
@@ -5053,6 +5037,9 @@
 Node* Document::Clone(Document& factory, CloneChildrenFlag flag) const {
   DCHECK_EQ(this, &factory)
       << "Document::Clone() doesn't support importNode mode.";
+
+  if (!execution_context_)
+    return nullptr;
   Document* clone = CloneDocumentWithoutChildren();
   clone->CloneDataFromDocument(*this);
   if (flag != CloneChildrenFlag::kSkip)
@@ -5978,21 +5965,21 @@
                          ExceptionState& exception_state) {
   UseCounter::Count(*this, WebFeature::kDocumentSetDomain);
 
-  const String feature_policy_error =
-      "Setting `document.domain` is disabled by Feature Policy.";
-  if (!IsFeatureEnabled(mojom::blink::FeaturePolicyFeature::kDocumentDomain,
-                        ReportOptions::kReportOnFailure,
-                        feature_policy_error)) {
-    exception_state.ThrowSecurityError(feature_policy_error);
-    return;
-  }
-
   if (!dom_window_) {
     exception_state.ThrowSecurityError(
         "A browsing context is required to set a domain.");
     return;
   }
 
+  const String feature_policy_error =
+      "Setting `document.domain` is disabled by Feature Policy.";
+  if (!GetExecutionContext()->IsFeatureEnabled(
+          mojom::blink::FeaturePolicyFeature::kDocumentDomain,
+          ReportOptions::kReportOnFailure, feature_policy_error)) {
+    exception_state.ThrowSecurityError(feature_policy_error);
+    return;
+  }
+
   if (IsSandboxed(network::mojom::blink::WebSandboxFlags::kDocumentDomain)) {
     exception_state.ThrowSecurityError(
         "Assignment is forbidden for sandboxed iframes.");
@@ -7188,9 +7175,9 @@
   if (!RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled()) {
     return true;
   }
-  if (!GetFrame() ||
-      IsFeatureEnabled(mojom::blink::FeaturePolicyFeature::kDocumentWrite,
-                       ReportOptions::kReportOnFailure)) {
+  if (!GetFrame() || GetExecutionContext()->IsFeatureEnabled(
+                         mojom::blink::FeaturePolicyFeature::kDocumentWrite,
+                         ReportOptions::kReportOnFailure)) {
     return true;
   }
 
@@ -8464,7 +8451,7 @@
   CountUse(uma_type);
   if (!RuntimeEnabledFeatures::BlockingFocusWithoutUserActivationEnabled())
     return true;
-  return IsFeatureEnabled(
+  return GetExecutionContext()->IsFeatureEnabled(
       mojom::blink::FeaturePolicyFeature::kFocusWithoutUserActivation);
 }
 
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index a5cf630a..f4e4c86 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -360,21 +360,6 @@
   v8::Isolate* GetIsolate() const;
   Agent* GetAgent() const;
   OriginTrialContext* GetOriginTrialContext() const;
-  bool IsFeatureEnabled(
-      mojom::blink::FeaturePolicyFeature,
-      ReportOptions report_on_failure = ReportOptions::kDoNotReport,
-      const String& message = g_empty_string) const;
-  bool IsFeatureEnabled(
-      mojom::blink::DocumentPolicyFeature,
-      ReportOptions report_option = ReportOptions::kDoNotReport,
-      const String& message = g_empty_string,
-      const String& source_file = g_empty_string) const;
-  bool IsFeatureEnabled(
-      mojom::blink::DocumentPolicyFeature,
-      PolicyValue threshold_value,
-      ReportOptions report_option = ReportOptions::kDoNotReport,
-      const String& message = g_empty_string,
-      const String& source_file = g_empty_string) const;
 
   String addressSpaceForBindings(ScriptState*) const;
 
diff --git a/third_party/blink/renderer/core/editing/commands/break_blockquote_command.cc b/third_party/blink/renderer/core/editing/commands/break_blockquote_command.cc
index 1675649b6..f112ca45 100644
--- a/third_party/blink/renderer/core/editing/commands/break_blockquote_command.cc
+++ b/third_party/blink/renderer/core/editing/commands/break_blockquote_command.cc
@@ -39,12 +39,28 @@
 #include "third_party/blink/renderer/core/html/html_quote_element.h"
 #include "third_party/blink/renderer/core/html_names.h"
 #include "third_party/blink/renderer/core/layout/layout_list_item.h"
+#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 
 namespace blink {
 
 namespace {
 
+base::Optional<int> GetListItemNumber(const Node* node) {
+  if (!node)
+    return base::nullopt;
+  // Because of elements with "display:list-item" has list item number,
+  // we use layout object instead of checking |HTMLLIElement|.
+  const LayoutObject* const layout_object = node->GetLayoutObject();
+  if (!layout_object)
+    return base::nullopt;
+  if (layout_object->IsLayoutNGListItem())
+    return ToLayoutNGListItem(layout_object)->Value();
+  if (layout_object->IsListItem())
+    return ToLayoutListItem(layout_object)->Value();
+  return base::nullopt;
+}
+
 bool IsFirstVisiblePositionInNode(const VisiblePosition& visible_position,
                                   const ContainerNode* node) {
   if (visible_position.IsNull())
@@ -234,11 +250,10 @@
       // find the first one so that we know where to start numbering.
       while (list_child_node && !IsA<HTMLLIElement>(*list_child_node))
         list_child_node = list_child_node->nextSibling();
-      if (IsListItem(list_child_node))
-        SetNodeAttribute(
-            &cloned_child, html_names::kStartAttr,
-            AtomicString::Number(
-                ToLayoutListItem(list_child_node->GetLayoutObject())->Value()));
+      if (auto list_item_number = GetListItemNumber(list_child_node)) {
+        SetNodeAttribute(&cloned_child, html_names::kStartAttr,
+                         AtomicString::Number(*list_item_number));
+      }
     }
 
     AppendNode(&cloned_child, cloned_ancestor, editing_state);
diff --git a/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc b/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
index caa62aa..f0233ad 100644
--- a/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
+++ b/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
@@ -981,6 +981,14 @@
   return placeholder;
 }
 
+static bool IsEmptyListItem(const LayoutBlockFlow& block_flow) {
+  if (block_flow.IsLayoutNGListItem())
+    return !block_flow.FirstChild();
+  if (block_flow.IsListItem())
+    return ToLayoutListItem(block_flow).IsEmpty();
+  return false;
+}
+
 HTMLBRElement* CompositeEditCommand::AddBlockPlaceholderIfNeeded(
     Element* container,
     EditingState* editing_state) {
@@ -995,8 +1003,7 @@
 
   // append the placeholder to make sure it follows
   // any unrendered blocks
-  if (block->Size().Height() == 0 ||
-      (block->IsListItem() && ToLayoutListItem(block)->IsEmpty()))
+  if (block->Size().Height() == 0 || IsEmptyListItem(*block))
     return AppendBlockPlaceholder(container, editing_state);
 
   return nullptr;
diff --git a/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc b/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc
index a3c0def..c668cc47 100644
--- a/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc
+++ b/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc
@@ -1378,7 +1378,7 @@
   Element* block_start = EnclosingBlock(insertion_pos.AnchorNode());
   if ((IsHTMLListElement(inserted_nodes.RefNode()) ||
        (IsHTMLListElement(inserted_nodes.RefNode()->firstChild()))) &&
-      block_start && block_start->GetLayoutObject()->IsListItem() &&
+      block_start && block_start->GetLayoutObject()->IsListItemIncludingNG() &&
       HasEditableStyle(*block_start->parentNode())) {
     inserted_nodes.SetRefNode(InsertAsListItems(
         To<HTMLElement>(inserted_nodes.RefNode()), block_start, insertion_pos,
diff --git a/third_party/blink/renderer/core/editing/editing_utilities.cc b/third_party/blink/renderer/core/editing/editing_utilities.cc
index d198257b..7c71208b 100644
--- a/third_party/blink/renderer/core/editing/editing_utilities.cc
+++ b/third_party/blink/renderer/core/editing/editing_utilities.cc
@@ -1115,7 +1115,8 @@
 }
 
 bool IsListItem(const Node* n) {
-  return n && n->GetLayoutObject() && n->GetLayoutObject()->IsListItem();
+  return n && n->GetLayoutObject() &&
+         n->GetLayoutObject()->IsListItemIncludingNG();
 }
 
 bool IsPresentationalHTMLElement(const Node* node) {
diff --git a/third_party/blink/renderer/core/editing/editor.cc b/third_party/blink/renderer/core/editing/editor.cc
index 40095fc..02b5f19 100644
--- a/third_party/blink/renderer/core/editing/editor.cc
+++ b/third_party/blink/renderer/core/editing/editor.cc
@@ -820,7 +820,7 @@
       EphemeralRangeInFlatTree::RangeOfContents(document);
   EphemeralRangeInFlatTree search_range(document_range);
 
-  bool forward = !(options & kBackwards);
+  const bool forward = !(options & kBackwards);
   bool start_in_reference_range = false;
   if (reference_range.IsNotNull()) {
     start_in_reference_range = options & kStartInSelection;
@@ -846,7 +846,10 @@
   // the reference range, find again. Build a selection with the found range
   // to remove collapsed whitespace. Compare ranges instead of selection
   // objects to ignore the way that the current selection was made.
-  if (result_range && start_in_reference_range &&
+  const bool find_next_if_selection_matches =
+      !(options & kDontFindNextIfSelectionMatches);
+  if (find_next_if_selection_matches && result_range &&
+      start_in_reference_range &&
       NormalizeRange(EphemeralRangeInFlatTree(result_range)) ==
           reference_range) {
     if (forward)
diff --git a/third_party/blink/renderer/core/editing/finder/find_options.h b/third_party/blink/renderer/core/editing/finder/find_options.h
index 6058284..0d85e61 100644
--- a/third_party/blink/renderer/core/editing/finder/find_options.h
+++ b/third_party/blink/renderer/core/editing/finder/find_options.h
@@ -37,6 +37,7 @@
   // TODO(yosin) Once find UI works on flat tree and it doesn't use
   // |rangeOfString()|, we should get rid of |FindAPICall| enum member.
   kFindAPICall = 1 << 5,  // Used for Window.find or execCommand('find')
+  kDontFindNextIfSelectionMatches = 1 << 6,
 };
 
 typedef unsigned FindOptions;
diff --git a/third_party/blink/renderer/core/editing/finder/find_task_controller.cc b/third_party/blink/renderer/core/editing/finder/find_task_controller.cc
index 0c27dbb..b775731 100644
--- a/third_party/blink/renderer/core/editing/finder/find_task_controller.cc
+++ b/third_party/blink/renderer/core/editing/finder/find_task_controller.cc
@@ -105,7 +105,7 @@
     blink::FindOptions find_options =
         (options_->forward ? 0 : kBackwards) |
         (options_->match_case ? 0 : kCaseInsensitive) |
-        (options_->find_next ? 0 : kStartInSelection);
+        (options_->new_session ? kStartInSelection : 0);
     auto start_time = base::TimeTicks::Now();
 
     while (search_start != search_end) {
diff --git a/third_party/blink/renderer/core/editing/finder/text_finder.cc b/third_party/blink/renderer/core/editing/finder/text_finder.cc
index a284abc..f63f1d27 100644
--- a/third_party/blink/renderer/core/editing/finder/text_finder.cc
+++ b/third_party/blink/renderer/core/editing/finder/text_finder.cc
@@ -135,7 +135,7 @@
                       const mojom::blink::FindOptions& options,
                       bool wrap_within_frame,
                       bool* active_now) {
-  if (!options.find_next) {
+  if (options.new_session) {
     // This find-in-page is redone due to the frame finishing loading.
     // If we can, just reuse the old active match;
     if (options.force && active_match_) {
@@ -169,17 +169,20 @@
       (options.forward ? 0 : kBackwards) |
       (options.match_case ? 0 : kCaseInsensitive) |
       (wrap_within_frame ? kWrapAround : 0) |
-      (options.find_next ? 0 : kStartInSelection);
+      (options.find_next_if_selection_matches
+           ? 0
+           : kDontFindNextIfSelectionMatches) |
+      (options.new_session ? kStartInSelection : 0);
   active_match_ = Editor::FindRangeOfString(
       *OwnerFrame().GetFrame()->GetDocument(), search_text,
       EphemeralRangeInFlatTree(active_match_.Get()), find_options);
 
   if (!active_match_) {
-    if (current_active_match_frame_ && !options.find_next)
+    if (current_active_match_frame_ && options.new_session)
       should_locate_active_rect_ = true;
-    // If we're finding next the next active match might not be in the current
+    // In an existing session the next active match might not be in
     // frame.  In this case we don't want to clear the matches cache.
-    if (!options.find_next)
+    if (options.new_session)
       ClearFindMatchesCache();
 
     InvalidatePaintForTickmarks();
@@ -213,7 +216,7 @@
   // Set this frame as focused.
   OwnerFrame().ViewImpl()->SetFocusedFrame(&OwnerFrame());
 
-  if (!options.find_next || active_selection || !is_active) {
+  if (options.new_session || active_selection || !is_active) {
     // This is either an initial Find operation, a Find-next from a new
     // start point due to a selection, or new matches were found during
     // Find-next due to DOM alteration (that couldn't be set as active), so
diff --git a/third_party/blink/renderer/core/editing/finder/text_finder_test.cc b/third_party/blink/renderer/core/editing/finder/text_finder_test.cc
index ad0efaa..00050f2c 100644
--- a/third_party/blink/renderer/core/editing/finder/text_finder_test.cc
+++ b/third_party/blink/renderer/core/editing/finder/text_finder_test.cc
@@ -108,7 +108,7 @@
   EXPECT_EQ(text_node, active_match->endContainer());
   EXPECT_EQ(10u, active_match->endOffset());
 
-  find_options->find_next = true;
+  find_options->new_session = false;
   ASSERT_TRUE(GetTextFinder().Find(identifier, search_text, *find_options,
                                    wrap_within_frame));
   active_match = GetTextFinder().ActiveMatch();
@@ -142,7 +142,7 @@
   EXPECT_EQ(text_node, active_match->endContainer());
   EXPECT_EQ(20u, active_match->endOffset());
 
-  find_options->find_next = true;
+  find_options->new_session = false;
   ASSERT_TRUE(GetTextFinder().Find(identifier, search_text, *find_options,
                                    wrap_within_frame));
   active_match = GetTextFinder().ActiveMatch();
@@ -248,7 +248,7 @@
   EXPECT_EQ(text_in_i_element, active_match->endContainer());
   EXPECT_EQ(3u, active_match->endOffset());
 
-  find_options->find_next = true;
+  find_options->new_session = false;
   ASSERT_TRUE(GetTextFinder().Find(identifier, search_text, *find_options,
                                    wrap_within_frame));
   active_match = GetTextFinder().ActiveMatch();
@@ -291,7 +291,7 @@
   EXPECT_EQ(text_in_b_element, active_match->endContainer());
   EXPECT_EQ(3u, active_match->endOffset());
 
-  find_options->find_next = true;
+  find_options->new_session = false;
   ASSERT_TRUE(GetTextFinder().Find(identifier, search_text, *find_options,
                                    wrap_within_frame));
   active_match = GetTextFinder().ActiveMatch();
@@ -502,7 +502,7 @@
   GetTextFinder().StartScopingStringMatches(identifier, search_text,
                                             *find_options);
 
-  find_options->find_next = true;
+  find_options->new_session = false;
   ASSERT_TRUE(GetTextFinder().Find(identifier, search_text, *find_options,
                                    wrap_within_frame, &active_now));
   EXPECT_TRUE(active_now);
@@ -525,7 +525,7 @@
   EXPECT_EQ(8u, active_match->endOffset());
 
   // Restart full search and check that added text is found.
-  find_options->find_next = false;
+  find_options->new_session = true;
   GetTextFinder().ResetMatchCount();
   GetTextFinder().CancelPendingScopingEffort();
   GetTextFinder().StartScopingStringMatches(identifier, search_text,
@@ -559,7 +559,7 @@
   GetTextFinder().StartScopingStringMatches(identifier, search_text,
                                             *find_options);
 
-  find_options->find_next = true;
+  find_options->new_session = false;
   ASSERT_FALSE(GetTextFinder().Find(identifier, search_text, *find_options,
                                     wrap_within_frame, &active_now));
   EXPECT_FALSE(active_now);
@@ -579,7 +579,7 @@
   EXPECT_EQ(8u, active_match->endOffset());
 
   // Restart full search and check that added text is found.
-  find_options->find_next = false;
+  find_options->new_session = true;
   GetTextFinder().ResetMatchCount();
   GetTextFinder().CancelPendingScopingEffort();
   GetTextFinder().StartScopingStringMatches(identifier, search_text,
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc
index f39b806..1b1d3726 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -5206,7 +5206,7 @@
   EXPECT_TRUE(find_in_page_client.FindResultsAreReady());
 
   // Find in a <div> element.
-  options->find_next = true;
+  options->new_session = false;
   EXPECT_TRUE(frame->GetFindInPage()->FindInternal(
       kFindIdentifier, search_text, *options, false, &active_now));
   EXPECT_TRUE(active_now);
@@ -5259,7 +5259,7 @@
 
   auto options = mojom::blink::FindOptions::New();
   options->run_synchronously_for_testing = true;
-  options->find_next = false;
+  options->new_session = true;
   options->forward = true;
   // The first search that will start the scoping process.
   frame->GetFindInPage()->Find(kFindIdentifier, search_pattern,
@@ -5270,7 +5270,7 @@
   EXPECT_EQ(2, find_in_page_client.Count());
   EXPECT_EQ(1, find_in_page_client.ActiveIndex());
 
-  options->find_next = true;
+  options->new_session = false;
   // The second search will jump to the next match without any scoping.
   frame->GetFindInPage()->Find(kFindIdentifier, search_pattern,
                                options->Clone());
@@ -5338,7 +5338,7 @@
 
   auto options = mojom::blink::FindOptions::New();
   options->run_synchronously_for_testing = true;
-  options->find_next = false;
+  options->new_session = true;
   options->forward = true;
   // First run.
   frame->GetFindInPage()->Find(kFindIdentifier, search_pattern,
@@ -5354,7 +5354,7 @@
   EXPECT_EQ(2, find_in_page_client.Count());
   EXPECT_EQ(1, find_in_page_client.ActiveIndex());
 
-  options->find_next = true;
+  options->new_session = false;
   options->force = false;
 
   frame->GetFindInPage()->Find(kFindIdentifier, search_pattern,
@@ -5363,7 +5363,7 @@
   EXPECT_EQ(2, find_in_page_client.Count());
   EXPECT_EQ(2, find_in_page_client.ActiveIndex());
 
-  options->find_next = false;
+  options->new_session = true;
   options->force = true;
 
   frame->GetFindInPage()->Find(kFindIdentifier, search_pattern,
diff --git a/third_party/blink/renderer/core/exported/web_navigation_params.cc b/third_party/blink/renderer/core/exported/web_navigation_params.cc
index b7b3168..8d64cd9 100644
--- a/third_party/blink/renderer/core/exported/web_navigation_params.cc
+++ b/third_party/blink/renderer/core/exported/web_navigation_params.cc
@@ -129,11 +129,12 @@
     const WebString& header_integrity,
     const WebURL& inner_url,
     const WebURLResponse& inner_response,
-    mojo::ScopedMessagePipeHandle loader_factory_handle)
+    CrossVariantMojoRemote<network::mojom::URLLoaderFactoryInterfaceBase>
+        loader_factory)
     : outer_url(outer_url),
       header_integrity(header_integrity),
       inner_url(inner_url),
       inner_response(inner_response),
-      loader_factory_handle(std::move(loader_factory_handle)) {}
+      loader_factory(std::move(loader_factory)) {}
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/exported/web_savable_resources_test_support.cc b/third_party/blink/renderer/core/exported/web_savable_resources_test_support.cc
index 76cc981..dfc5be29 100644
--- a/third_party/blink/renderer/core/exported/web_savable_resources_test_support.cc
+++ b/third_party/blink/renderer/core/exported/web_savable_resources_test_support.cc
@@ -12,7 +12,8 @@
 namespace blink {
 
 WebString GetSubResourceLinkFromElementForTesting(const WebElement& element) {
-  return WebString(SavableResources::GetSubResourceLinkFromElement(element));
+  return WebString(SavableResources::GetSubResourceLinkFromElement(
+      static_cast<Element*>(element)));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc b/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc
index a5be54a..07986bf 100644
--- a/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc
+++ b/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc
@@ -9,6 +9,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/loader/empty_clients.h"
 #include "third_party/blink/renderer/core/testing/page_test_base.h"
@@ -878,23 +879,23 @@
       "Blink.UseCounter.FeaturePolicy.PotentialViolation";
   auto dummy_page_holder_ = std::make_unique<DummyPageHolder>();
   // Probing feature state should not count.
-  dummy_page_holder_->GetDocument().IsFeatureEnabled(
+  dummy_page_holder_->GetFrame().DomWindow()->IsFeatureEnabled(
       mojom::blink::FeaturePolicyFeature::kPayment);
   tester.ExpectTotalCount(histogram_name, 0);
   // Checking the feature state with reporting intent should record a potential
   // violation.
-  dummy_page_holder_->GetDocument().IsFeatureEnabled(
+  dummy_page_holder_->GetFrame().DomWindow()->IsFeatureEnabled(
       mojom::blink::FeaturePolicyFeature::kPayment,
       ReportOptions::kReportOnFailure);
   tester.ExpectTotalCount(histogram_name, 1);
   // The potential violation for an already recorded violation does not count
   // again.
-  dummy_page_holder_->GetDocument().IsFeatureEnabled(
+  dummy_page_holder_->GetFrame().DomWindow()->IsFeatureEnabled(
       mojom::blink::FeaturePolicyFeature::kPayment,
       ReportOptions::kReportOnFailure);
   tester.ExpectTotalCount(histogram_name, 1);
   // Sanity check: check some other feature to increase the count.
-  dummy_page_holder_->GetDocument().IsFeatureEnabled(
+  dummy_page_holder_->GetFrame().DomWindow()->IsFeatureEnabled(
       mojom::blink::FeaturePolicyFeature::kFullscreen,
       ReportOptions::kReportOnFailure);
   tester.ExpectTotalCount(histogram_name, 2);
diff --git a/third_party/blink/renderer/core/frame/find_in_page.cc b/third_party/blink/renderer/core/frame/find_in_page.cc
index 8f65b9cb..e8a29fb 100644
--- a/third_party/blink/renderer/core/frame/find_in_page.cc
+++ b/third_party/blink/renderer/core/frame/find_in_page.cc
@@ -70,7 +70,7 @@
   blink::WebPlugin* plugin = GetWebPluginForFind();
   // Check if the plugin still exists in the document.
   if (plugin) {
-    if (options->find_next) {
+    if (!options->new_session) {
       // Just navigate back/forward.
       plugin->SelectFindResult(options->forward, request_id);
       LocalFrame* core_frame = frame_->GetFrame();
@@ -95,20 +95,20 @@
   bool result = false;
   bool active_now = false;
 
-  if (!options->find_next) {
+  if (options->new_session) {
     // If this is an initial find request, cancel any pending scoping effort
     // done by the previous find request.
     EnsureTextFinder().CancelPendingScopingEffort();
   }
 
-  // Search for an active match only if this frame is focused or if this is a
-  // find next
-  if (frame_->IsFocused() || options->find_next) {
+  // Search for an active match only if this frame is focused or if this is an
+  // existing session.
+  if (frame_->IsFocused() || !options->new_session) {
     result = FindInternal(request_id, search_text, *options,
                           false /* wrap_within_frame */, &active_now);
   }
 
-  if (result && !options->find_next) {
+  if (result && options->new_session) {
     // Indicate that at least one match has been found. 1 here means
     // possibly more matches could be coming.
     ReportFindInPageMatchCount(request_id, 1 /* count */,
@@ -117,8 +117,7 @@
 
   // There are three cases in which scoping is needed:
   //
-  // (1) This is an initial find request (|options.findNext| is false). This
-  // will be the first scoping effort for this find session.
+  // (1) This is a new find session. This will be its first scoping effort.
   //
   // (2) Something has been selected since the last search. This means that we
   // cannot just increment the current match ordinal; we need to re-generate
@@ -133,7 +132,7 @@
   //
   // If none of these cases are true, then we just report the current match
   // count without scoping.
-  if (/* (1) */ options->find_next && /* (2) */ current_selection.IsNull() &&
+  if (/* (1) */ !options->new_session && /* (2) */ current_selection.IsNull() &&
       /* (3) */ !(result && !active_now)) {
     // Force report of the actual count.
     EnsureTextFinder().IncreaseMatchCount(request_id, 0);
@@ -150,13 +149,13 @@
                                        const WebString& search_text,
                                        bool match_case,
                                        bool forward,
-                                       bool find_next,
+                                       bool new_session,
                                        bool force,
                                        bool wrap_within_frame) {
   auto options = mojom::blink::FindOptions::New();
   options->match_case = match_case;
   options->forward = forward;
-  options->find_next = find_next;
+  options->new_session = new_session;
   options->force = force;
   options->run_synchronously_for_testing = true;
   bool result = find_in_page_->FindInternal(identifier, search_text, *options,
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index d3f3962..0525678 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -1061,14 +1061,9 @@
 }
 
 FloatSize LocalFrameView::ViewportSizeForMediaQueries() const {
-  FloatSize viewport_size(layout_size_);
-  if (!frame_->GetDocument()->Printing()) {
-    float zoom = GetFrame().PageZoomFactor();
-    viewport_size.SetWidth(
-        AdjustForAbsoluteZoom::AdjustInt(layout_size_.Width(), zoom));
-    viewport_size.SetHeight(
-        AdjustForAbsoluteZoom::AdjustInt(layout_size_.Height(), zoom));
-  }
+  FloatSize viewport_size(GetLayoutSize());
+  if (!frame_->GetDocument() || !frame_->GetDocument()->Printing())
+    viewport_size.Scale(1 / GetFrame().PageZoomFactor());
   return viewport_size;
 }
 
@@ -1225,7 +1220,6 @@
       SetMediaType(media_type_when_not_printing_);
     media_type_when_not_printing_ = g_null_atom;
   }
-  frame_->GetDocument()->GetStyleEngine().PrintingStateChanged();
 }
 
 void LocalFrameView::AddBackgroundAttachmentFixedObject(LayoutObject* object) {
diff --git a/third_party/blink/renderer/core/frame/savable_resources.cc b/third_party/blink/renderer/core/frame/savable_resources.cc
index cc5e7bd..b4a4f6a 100644
--- a/third_party/blink/renderer/core/frame/savable_resources.cc
+++ b/third_party/blink/renderer/core/frame/savable_resources.cc
@@ -6,24 +6,25 @@
 
 #include "third_party/blink/public/mojom/frame/frame.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/web/web_document.h"
-#include "third_party/blink/public/web/web_element.h"
-#include "third_party/blink/public/web/web_element_collection.h"
-#include "third_party/blink/public/web/web_input_element.h"
-#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
+#include "third_party/blink/renderer/core/html/html_all_collection.h"
+#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
+#include "third_party/blink/renderer/core/html_names.h"
+#include "third_party/blink/renderer/core/input_type_names.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
 namespace {
 
-// Returns |true| if |web_frame| contains (or should be assumed to contain)
+// Returns |true| if |frame| contains (or should be assumed to contain)
 // a html document.
-bool DoesFrameContainHtmlDocument(WebFrame* web_frame,
-                                  const WebElement& element) {
-  if (web_frame->IsWebLocalFrame()) {
-    WebDocument doc = web_frame->ToWebLocalFrame()->GetDocument();
-    return doc.IsHTMLDocument() || doc.IsXHTMLDocument();
+bool DoesFrameContainHtmlDocument(Frame* frame, Element* element) {
+  if (frame->IsLocalFrame()) {
+    Document* document =
+        LocalFrame::FromFrameToken(frame->GetFrameToken())->GetDocument();
+    return document->IsHTMLDocument() || document->IsXHTMLDocument();
   }
 
   // Cannot inspect contents of a remote frame, so we use a heuristic:
@@ -34,28 +35,31 @@
   // following caveats: 1) original frame content will be saved and 2) links
   // in frame's html doc will not be rewritten to point to locally saved
   // files.
-  return element.HasHTMLTagName("iframe") || element.HasHTMLTagName("frame");
+  return element->HasTagName(html_names::kIFrameTag) ||
+         element->HasTagName(html_names::kFrameTag);
 }
 
 // If present and valid, then push the link associated with |element|
-// into either WebSavableResources::ResultImpl::subframes or
-// WebSavableResources::ResultImpl::resources_list.
-void GetSavableResourceLinkForElement(const WebElement& element,
-                                      const WebDocument& current_doc,
+// into either SavableResources::Result::subframes_ or
+// SavableResources::Result::resources_list_.
+void GetSavableResourceLinkForElement(Element* element,
+                                      const Document& current_document,
                                       SavableResources::Result* result) {
   // Get absolute URL.
   String link_attribute_value =
       SavableResources::GetSubResourceLinkFromElement(element);
-  KURL element_url = current_doc.CompleteURL(link_attribute_value);
+  KURL element_url = current_document.CompleteURL(link_attribute_value);
 
   // See whether to report this element as a subframe.
-  WebFrame* web_frame = WebFrame::FromFrameOwnerElement(element);
-  if (web_frame && DoesFrameContainHtmlDocument(web_frame, element)) {
-    mojom::blink::SavableSubframePtr subframe =
-        mojom::blink::SavableSubframe::New(element_url,
-                                           web_frame->GetFrameToken());
-    result->AppendSubframe(std::move(subframe));
-    return;
+  if (auto* frame_owner = DynamicTo<HTMLFrameOwnerElement>(element)) {
+    Frame* content_frame = frame_owner->ContentFrame();
+    if (content_frame && DoesFrameContainHtmlDocument(content_frame, element)) {
+      mojom::blink::SavableSubframePtr subframe =
+          mojom::blink::SavableSubframe::New(element_url,
+                                             content_frame->GetFrameToken());
+      result->AppendSubframe(std::move(subframe));
+      return;
+    }
   }
 
   // Check whether the node has sub resource URL or not.
@@ -94,44 +98,50 @@
     return false;
 
   // Get current using document.
-  WebDocument current_doc = current_frame->GetDocument();
+  Document* current_document = current_frame->GetDocument();
+  DCHECK(current_document);
+
   // Go through all descent nodes.
-  WebElementCollection all = current_doc.All();
+  HTMLAllCollection* collection = current_document->all();
+
   // Go through all elements in this frame.
-  for (WebElement element = all.FirstItem(); !element.IsNull();
-       element = all.NextItem()) {
-    GetSavableResourceLinkForElement(element, current_doc, result);
+  for (unsigned i = 0; i < collection->length(); ++i) {
+    GetSavableResourceLinkForElement(collection->item(i), *current_document,
+                                     result);
   }
 
   return true;
 }
 
 // static
-String SavableResources::GetSubResourceLinkFromElement(
-    const WebElement& element) {
+String SavableResources::GetSubResourceLinkFromElement(Element* element) {
   const char* attribute_name = nullptr;
-  if (element.HasHTMLTagName("img") || element.HasHTMLTagName("frame") ||
-      element.HasHTMLTagName("iframe") || element.HasHTMLTagName("script")) {
+  if (element->HasTagName(html_names::kImgTag) ||
+      element->HasTagName(html_names::kFrameTag) ||
+      element->HasTagName(html_names::kIFrameTag) ||
+      element->HasTagName(html_names::kScriptTag)) {
     attribute_name = "src";
-  } else if (element.HasHTMLTagName("input")) {
-    const WebInputElement input = element.ToConst<WebInputElement>();
-    if (input.IsImageButton()) {
+  } else if (element->HasTagName(html_names::kInputTag)) {
+    HTMLInputElement* input = To<HTMLInputElement>(element);
+    if (input->type() == input_type_names::kImage) {
       attribute_name = "src";
     }
-  } else if (element.HasHTMLTagName("body") ||
-             element.HasHTMLTagName("table") || element.HasHTMLTagName("tr") ||
-             element.HasHTMLTagName("td")) {
+  } else if (element->HasTagName(html_names::kBodyTag) ||
+             element->HasTagName(html_names::kTableTag) ||
+             element->HasTagName(html_names::kTrTag) ||
+             element->HasTagName(html_names::kTdTag)) {
     attribute_name = "background";
-  } else if (element.HasHTMLTagName("blockquote") ||
-             element.HasHTMLTagName("q") || element.HasHTMLTagName("del") ||
-             element.HasHTMLTagName("ins")) {
+  } else if (element->HasTagName(html_names::kBlockquoteTag) ||
+             element->HasTagName(html_names::kQTag) ||
+             element->HasTagName(html_names::kDelTag) ||
+             element->HasTagName(html_names::kInsTag)) {
     attribute_name = "cite";
-  } else if (element.HasHTMLTagName("object")) {
+  } else if (element->HasTagName(html_names::kObjectTag)) {
     attribute_name = "data";
-  } else if (element.HasHTMLTagName("link")) {
+  } else if (element->HasTagName(html_names::kLinkTag)) {
     // If the link element is not linked to css, ignore it.
-    String type = element.GetAttribute("type");
-    String rel = element.GetAttribute("rel");
+    String type = element->getAttribute("type");
+    String rel = element->getAttribute("rel");
     if ((type.ContainsOnlyASCIIOrEmpty() && type.LowerASCII() == "text/css") ||
         (rel.ContainsOnlyASCIIOrEmpty() && rel.LowerASCII() == "stylesheet")) {
       // TODO(jnd): Add support for extracting links of sub-resources which
@@ -142,7 +152,7 @@
   }
   if (!attribute_name)
     return String();
-  String value = element.GetAttribute(String::FromUTF8(attribute_name));
+  String value = element->getAttribute(attribute_name);
   // If value has content and not start with "javascript:" then return it,
   // otherwise return an empty string.
   if (!value.IsNull() && !value.IsEmpty() &&
diff --git a/third_party/blink/renderer/core/frame/savable_resources.h b/third_party/blink/renderer/core/frame/savable_resources.h
index 306f789..d2729f3 100644
--- a/third_party/blink/renderer/core/frame/savable_resources.h
+++ b/third_party/blink/renderer/core/frame/savable_resources.h
@@ -14,8 +14,8 @@
 
 namespace blink {
 
+class Element;
 class LocalFrame;
-class WebElement;
 
 class SavableResources {
   STATIC_ONLY(SavableResources);
@@ -54,8 +54,8 @@
   // INPUT TYPE=image, returns the value in "src". For LINK TYPE=text/css,
   // returns the value in "href". For BODY, TABLE, TR, TD, returns the value in
   // "background". For BLOCKQUOTE, Q, DEL, INS, returns the value in "cite"
-  // attribute. Otherwise returns a null WebString.
-  static String GetSubResourceLinkFromElement(const WebElement& element);
+  // attribute. Otherwise returns an empty String.
+  static String GetSubResourceLinkFromElement(Element* element);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/settings.json5 b/third_party/blink/renderer/core/frame/settings.json5
index 5335312..96fa854 100644
--- a/third_party/blink/renderer/core/frame/settings.json5
+++ b/third_party/blink/renderer/core/frame/settings.json5
@@ -910,12 +910,6 @@
       invalidate: "ForceDark",
     },
     {
-      name: "forceDarkModeClassifierType",
-      initial: "DarkModeClassifierType::kGeneric",
-      type: "DarkModeClassifierType",
-      invalidate: "ForceDark",
-    },
-    {
       name: "forceDarkModeImagePolicy",
       initial: "DarkModeImagePolicy::kFilterNone",
       type: "DarkModeImagePolicy",
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
index 720938d..e81e5f7f 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.h
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
@@ -250,7 +250,7 @@
                       bool match_case,
                       bool forward,
                       bool force,
-                      bool find_next,
+                      bool new_session,
                       bool wrap_within_frame) override;
   void SetTickmarks(const WebVector<WebRect>&) override;
   WebNode ContextMenuNode() const override;
diff --git a/third_party/blink/renderer/core/fullscreen/fullscreen.cc b/third_party/blink/renderer/core/fullscreen/fullscreen.cc
index 843cfffc..e4a1f3567 100644
--- a/third_party/blink/renderer/core/fullscreen/fullscreen.cc
+++ b/third_party/blink/renderer/core/fullscreen/fullscreen.cc
@@ -220,7 +220,7 @@
 
   // 2. If Feature Policy is enabled, return the policy for "fullscreen"
   // feature.
-  return document.IsFeatureEnabled(
+  return document.GetExecutionContext()->IsFeatureEnabled(
       mojom::blink::FeaturePolicyFeature::kFullscreen, report_on_failure);
 }
 
diff --git a/third_party/blink/renderer/core/html/BUILD.gn b/third_party/blink/renderer/core/html/BUILD.gn
index 1a5d83f..7e00bd6 100644
--- a/third_party/blink/renderer/core/html/BUILD.gn
+++ b/third_party/blink/renderer/core/html/BUILD.gn
@@ -465,6 +465,8 @@
     "link_resource.h",
     "link_style.cc",
     "link_style.h",
+    "link_web_bundle.cc",
+    "link_web_bundle.h",
     "list_item_ordinal.cc",
     "list_item_ordinal.h",
     "loading_attribute.cc",
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
index 28fe0bd..e78b473 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
@@ -8,6 +8,9 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_metrics.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_participation.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/core/dom/document.h"
@@ -146,6 +149,7 @@
     ToBlobFunctionType function_type,
     base::TimeTicks start_time,
     ExecutionContext* context,
+    base::Optional<UkmParameters> ukm_params,
     ScriptPromiseResolver* resolver)
     : CanvasAsyncBlobCreator(image,
                              options,
@@ -153,6 +157,7 @@
                              nullptr,
                              start_time,
                              context,
+                             ukm_params,
                              resolver) {}
 
 CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(
@@ -162,6 +167,7 @@
     V8BlobCallback* callback,
     base::TimeTicks start_time,
     ExecutionContext* context,
+    base::Optional<UkmParameters> ukm_params,
     ScriptPromiseResolver* resolver)
     : fail_encoder_initialization_for_test_(false),
       enforce_idle_encoding_for_test_(false),
@@ -172,6 +178,7 @@
       start_time_(start_time),
       static_bitmap_image_loaded_(false),
       callback_(callback),
+      ukm_params_(ukm_params),
       script_promise_resolver_(resolver) {
   DCHECK(image);
   DCHECK(context);
@@ -468,6 +475,8 @@
                              WrapPersistent(result_blob)));
   }
 
+  RecordIdentifiabilityMetric();
+
   RecordScaledDurationHistogram(mime_type_,
                                 base::TimeTicks::Now() - start_time_,
                                 image_->width(), image_->height());
@@ -475,6 +484,33 @@
   Dispose();
 }
 
+void CanvasAsyncBlobCreator::RecordIdentifiabilityMetric() {
+  if (!ukm_params_.has_value() || !IsUserInIdentifiabilityStudy())
+    return;
+  // Creating this ImageDataBuffer has some overhead, namely getting the SkImage
+  // and computing the pixmap.
+  context_->GetTaskRunner(TaskType::kInternalDefault)
+      ->PostTask(
+          FROM_HERE,
+          WTF::Bind(
+              [](scoped_refptr<StaticBitmapImage> image,
+                 UkmParameters ukm_params) {
+                std::unique_ptr<ImageDataBuffer> data_buffer =
+                    ImageDataBuffer::Create(image);
+                if (!data_buffer)
+                  return;
+                blink::IdentifiabilityMetricBuilder(ukm_params.source_id)
+                    .Set(blink::IdentifiableSurface::FromTypeAndInput(
+                             blink::IdentifiableSurface::Type::kCanvasReadback,
+                             0),
+                         blink::IdentifiabilityDigestOfBytes(
+                             base::make_span(data_buffer->Pixels(),
+                                             data_buffer->ComputeByteSize())))
+                    .Record(ukm_params.ukm_recorder);
+              },
+              image_, ukm_params_.value()));
+}
+
 void CanvasAsyncBlobCreator::CreateNullAndReturnResult() {
   RecordIdleTaskStatusHistogram(idle_task_status_);
   if (function_type_ == kHTMLCanvasToBlobCallback) {
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h
index fdd8d7d..1a97de91 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h
+++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h
@@ -8,11 +8,14 @@
 #include <memory>
 
 #include "base/location.h"
+#include "base/optional.h"
 #include "base/single_thread_task_runner.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_blob_callback.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_image_encode_options.h"
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/html/canvas/ukm_parameters.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
 #include "third_party/blink/renderer/platform/geometry/int_size.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_types.h"
@@ -60,6 +63,7 @@
                          ToBlobFunctionType function_type,
                          base::TimeTicks start_time,
                          ExecutionContext*,
+                         base::Optional<UkmParameters> ukm_params,
                          ScriptPromiseResolver*);
   CanvasAsyncBlobCreator(scoped_refptr<StaticBitmapImage>,
                          const ImageEncodeOptions*,
@@ -67,6 +71,7 @@
                          V8BlobCallback*,
                          base::TimeTicks start_time,
                          ExecutionContext*,
+                         base::Optional<UkmParameters> ukm_params,
                          ScriptPromiseResolver* = nullptr);
   virtual ~CanvasAsyncBlobCreator();
 
@@ -132,6 +137,8 @@
   // Used for HTMLCanvasElement only
   Member<V8BlobCallback> callback_;
 
+  base::Optional<UkmParameters> ukm_params_;
+
   // Used for OffscreenCanvas only
   Member<ScriptPromiseResolver> script_promise_resolver_;
 
@@ -147,6 +154,8 @@
 
   void IdleTaskStartTimeoutEvent(double quality);
   void IdleTaskCompleteTimeoutEvent();
+
+  void RecordIdentifiabilityMetric();
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
index 0284f1bc..c68359ce 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
@@ -35,6 +35,7 @@
             nullptr,
             base::TimeTicks(),
             document->GetExecutionContext(),
+            base::make_optional<UkmParameters>(),
             nullptr) {
     if (fail_encoder_initialization)
       fail_encoder_initialization_for_test_ = true;
@@ -129,7 +130,6 @@
   void TearDown() override;
 
  private:
-
   Persistent<MockCanvasAsyncBlobCreator> async_blob_creator_;
 };
 
@@ -264,7 +264,8 @@
                                          kDisplayP3ImageColorSpaceName,
                                          kRec2020ImageColorSpaceName};
   std::list<String> blob_pixel_formats = {
-      kRGBA8ImagePixelFormatName, kRGBA16ImagePixelFormatName,
+      kRGBA8ImagePixelFormatName,
+      kRGBA16ImagePixelFormatName,
   };
 
   // Maximum differences are both observed locally with
@@ -295,7 +296,8 @@
                   source_bitmap_image, options,
                   CanvasAsyncBlobCreator::ToBlobFunctionType::
                       kHTMLCanvasConvertToBlobPromise,
-                  base::TimeTicks(), GetFrame().DomWindow(), nullptr);
+                  base::TimeTicks(), GetFrame().DomWindow(),
+                  base::make_optional<UkmParameters>(), nullptr);
           ASSERT_TRUE(async_blob_creator->EncodeImageForConvertToBlobTest());
 
           sk_sp<SkData> sk_data = SkData::MakeWithCopy(
@@ -326,4 +328,4 @@
     }
   }
 }
-}
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
index 0bd1167..56200e9 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
@@ -330,7 +330,7 @@
     }
     auto* async_creator = MakeGarbageCollected<CanvasAsyncBlobCreator>(
         image_bitmap, options, function_type, start_time,
-        ExecutionContext::From(script_state), resolver);
+        ExecutionContext::From(script_state), ukm_params_, resolver);
     async_creator->ScheduleAsyncBlobCreation(options->quality());
     return resolver->Promise();
   }
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index ba67a352..23d0daa2 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -377,12 +377,6 @@
     ScriptState* script_state,
     const ImageEncodeOptions* options,
     ExceptionState& exception_state) {
-  RecordIdentifiabilityMetric(
-      blink::IdentifiableSurface::FromTypeAndInput(
-          blink::IdentifiableSurface::Type::kCanvasReadback,
-          context_ ? context_->GetContextType()
-                   : CanvasRenderingContext::kContextTypeUnknown),
-      0);
   return CanvasRenderingContextHost::convertToBlob(script_state, options,
                                                    exception_state);
 }
@@ -970,7 +964,8 @@
     RecordIdentifiabilityMetric(
         blink::IdentifiableSurface::FromTypeAndInput(
             blink::IdentifiableSurface::Type::kCanvasReadback, final_digest),
-        blink::IdentifiabilityDigestOfBytes(data_url.Span8()));
+        blink::IdentifiabilityDigestOfBytes(base::make_span(
+            data_buffer->Pixels(), data_buffer->ComputeByteSize())));
     return data_url;
   }
 
@@ -1037,16 +1032,11 @@
     async_creator = MakeGarbageCollected<CanvasAsyncBlobCreator>(
         image_bitmap, options,
         CanvasAsyncBlobCreator::kHTMLCanvasToBlobCallback, callback, start_time,
-        GetExecutionContext());
+        GetExecutionContext(),
+        base::make_optional<UkmParameters>(
+            {GetDocument().UkmRecorder(), GetDocument().UkmSourceID()}));
   }
 
-  RecordIdentifiabilityMetric(
-      blink::IdentifiableSurface::FromTypeAndInput(
-          blink::IdentifiableSurface::Type::kCanvasReadback,
-          context_ ? context_->GetContextType()
-                   : CanvasRenderingContext::kContextTypeUnknown),
-      0);
-
   if (async_creator) {
     async_creator->ScheduleAsyncBlobCreation(quality);
   } else {
diff --git a/third_party/blink/renderer/core/html/html_attribute_names.json5 b/third_party/blink/renderer/core/html/html_attribute_names.json5
index 6a53ffa3..457436a9 100644
--- a/third_party/blink/renderer/core/html/html_attribute_names.json5
+++ b/third_party/blink/renderer/core/html/html_attribute_names.json5
@@ -283,6 +283,7 @@
     "rel",
     "reportingorigin",
     "required",
+    "resources",
     "rev",
     "reversed",
     "role",
diff --git a/third_party/blink/renderer/core/html/html_iframe_element.cc b/third_party/blink/renderer/core/html/html_iframe_element.cc
index 37e8a0d..5316549 100644
--- a/third_party/blink/renderer/core/html/html_iframe_element.cc
+++ b/third_party/blink/renderer/core/html/html_iframe_element.cc
@@ -497,13 +497,14 @@
           network::mojom::blink::TrustTokenOperationType::kSigning;
 
   if (operation_requires_feature_policy &&
-      (!GetDocument().IsFeatureEnabled(
+      (!GetExecutionContext()->IsFeatureEnabled(
           mojom::blink::FeaturePolicyFeature::kTrustTokenRedemption))) {
-    GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
-        mojom::blink::ConsoleMessageSource::kOther,
-        mojom::blink::ConsoleMessageLevel::kError,
-        "Trust Tokens: Attempted redemption or signing without the "
-        "trust-token-redemption Feature Policy feature present."));
+    GetExecutionContext()->AddConsoleMessage(
+        MakeGarbageCollected<ConsoleMessage>(
+            mojom::blink::ConsoleMessageSource::kOther,
+            mojom::blink::ConsoleMessageLevel::kError,
+            "Trust Tokens: Attempted redemption or signing without the "
+            "trust-token-redemption Feature Policy feature present."));
     return nullptr;
   }
 
diff --git a/third_party/blink/renderer/core/html/html_image_element.cc b/third_party/blink/renderer/core/html/html_image_element.cc
index 010b716..eb821c28 100644
--- a/third_party/blink/renderer/core/html/html_image_element.cc
+++ b/third_party/blink/renderer/core/html/html_image_element.cc
@@ -104,7 +104,7 @@
       is_fallback_image_(false),
       is_default_overridden_intrinsic_size_(
           !document.IsImageDocument() &&
-          !document.IsFeatureEnabled(
+          !GetExecutionContext()->IsFeatureEnabled(
               mojom::blink::DocumentPolicyFeature::kUnsizedMedia)),
       is_legacy_format_or_unoptimized_image_(false),
       referrer_policy_(network::mojom::ReferrerPolicy::kDefault) {
diff --git a/third_party/blink/renderer/core/html/html_link_element.cc b/third_party/blink/renderer/core/html/html_link_element.cc
index 0db6448f..176ba0ec 100644
--- a/third_party/blink/renderer/core/html/html_link_element.cc
+++ b/third_party/blink/renderer/core/html/html_link_element.cc
@@ -41,6 +41,7 @@
 #include "third_party/blink/renderer/core/html/cross_origin_attribute.h"
 #include "third_party/blink/renderer/core/html/imports/link_import.h"
 #include "third_party/blink/renderer/core/html/link_manifest.h"
+#include "third_party/blink/renderer/core/html/link_web_bundle.h"
 #include "third_party/blink/renderer/core/html_names.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/loader/link_loader.h"
@@ -141,6 +142,11 @@
              RuntimeEnabledFeatures::PriorityHintsEnabled(&GetDocument())) {
     UseCounter::Count(GetDocument(), WebFeature::kPriorityHints);
     importance_ = value;
+  } else if (name == html_names::kResourcesAttr &&
+             RuntimeEnabledFeatures::SubresourceWebBundlesEnabled(
+                 &GetDocument())) {
+    resources_ = value;
+    Process();
   } else if (name == html_names::kDisabledAttr) {
     UseCounter::Count(GetDocument(), WebFeature::kHTMLLinkElementDisabled);
     if (params.reason == AttributeModificationReason::kByParser)
@@ -223,6 +229,11 @@
       if (!RuntimeEnabledFeatures::HTMLImportsEnabled(&GetDocument()))
         return nullptr;
       link_ = MakeGarbageCollected<LinkImport>(this);
+    } else if (rel_attribute_.IsWebBundle()) {
+      // Only create a webbundle link when SubresourceWebBundles are enabled.
+      if (!RuntimeEnabledFeatures::SubresourceWebBundlesEnabled(&GetDocument()))
+        return nullptr;
+      link_ = MakeGarbageCollected<LinkWebBundle>(this);
     } else if (rel_attribute_.IsManifest()) {
       link_ = MakeGarbageCollected<LinkManifest>(this);
     } else {
diff --git a/third_party/blink/renderer/core/html/html_link_element.h b/third_party/blink/renderer/core/html/html_link_element.h
index bfad5af..d03829af 100644
--- a/third_party/blink/renderer/core/html/html_link_element.h
+++ b/third_party/blink/renderer/core/html/html_link_element.h
@@ -169,6 +169,7 @@
   String media_;
   String integrity_;
   String importance_;
+  String resources_;
   network::mojom::ReferrerPolicy referrer_policy_;
   Member<DOMTokenList> sizes_;
   Vector<gfx::Size> icon_sizes_;
diff --git a/third_party/blink/renderer/core/html/html_link_element.idl b/third_party/blink/renderer/core/html/html_link_element.idl
index f890890..87e35ce 100644
--- a/third_party/blink/renderer/core/html/html_link_element.idl
+++ b/third_party/blink/renderer/core/html/html_link_element.idl
@@ -58,4 +58,9 @@
     // Subresource Integrity
     // https://w3c.github.io/webappsec-subresource-integrity/#HTMLLinkElement
     [Reflect] attribute DOMString integrity;
+
+    // Subresource loading with Web Bundles
+    // https://github.com/WICG/webpackage/blob/master/explainers/subresource-loading.md
+    // crbug.com/1082020
+    [RuntimeEnabled=SubresourceWebBundles, CEReactions, Reflect] attribute USVString resources;
 };
diff --git a/third_party/blink/renderer/core/html/link_rel_attribute.cc b/third_party/blink/renderer/core/html/link_rel_attribute.cc
index c4d5fdd..acdd004 100644
--- a/third_party/blink/renderer/core/html/link_rel_attribute.cc
+++ b/third_party/blink/renderer/core/html/link_rel_attribute.cc
@@ -50,7 +50,8 @@
       is_module_preload_(false),
       is_service_worker_(false),
       is_canonical_(false),
-      is_monetization_(false) {}
+      is_monetization_(false),
+      is_web_bundle_(false) {}
 
 LinkRelAttribute::LinkRelAttribute(const String& rel) : LinkRelAttribute() {
   if (rel.IsEmpty())
@@ -102,6 +103,8 @@
       is_canonical_ = true;
     } else if (EqualIgnoringASCIICase(link_type, "monetization")) {
       is_monetization_ = true;
+    } else if (EqualIgnoringASCIICase(link_type, "webbundle")) {
+      is_web_bundle_ = true;
     }
     // Adding or removing a value here requires you to update
     // RelList::supportedTokens()
diff --git a/third_party/blink/renderer/core/html/link_rel_attribute.h b/third_party/blink/renderer/core/html/link_rel_attribute.h
index 309cbcb..37f6ebf2 100644
--- a/third_party/blink/renderer/core/html/link_rel_attribute.h
+++ b/third_party/blink/renderer/core/html/link_rel_attribute.h
@@ -61,6 +61,7 @@
   bool IsServiceWorker() const { return is_service_worker_; }
   bool IsCanonical() const { return is_canonical_; }
   bool IsMonetization() const { return is_monetization_; }
+  bool IsWebBundle() const { return is_web_bundle_; }
 
  private:
   mojom::blink::FaviconIconType icon_type_;
@@ -78,6 +79,7 @@
   bool is_service_worker_ : 1;
   bool is_canonical_ : 1;
   bool is_monetization_ : 1;
+  bool is_web_bundle_ : 1;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/link_rel_attribute_test.cc b/third_party/blink/renderer/core/html/link_rel_attribute_test.cc
index c4a142f..5b6c3ba 100644
--- a/third_party/blink/renderer/core/html/link_rel_attribute_test.cc
+++ b/third_party/blink/renderer/core/html/link_rel_attribute_test.cc
@@ -43,7 +43,8 @@
                                         bool is_link_prerender,
                                         bool is_import = false,
                                         bool is_preconnect = false,
-                                        bool is_canonical = false) {
+                                        bool is_canonical = false,
+                                        bool is_web_bundle = false) {
   SCOPED_TRACE(value.Utf8());
   LinkRelAttribute link_rel_attribute(value);
   ASSERT_EQ(is_style_sheet, link_rel_attribute.IsStyleSheet());
@@ -54,6 +55,7 @@
   ASSERT_EQ(is_import, link_rel_attribute.IsImport());
   ASSERT_EQ(is_preconnect, link_rel_attribute.IsPreconnect());
   ASSERT_EQ(is_canonical, link_rel_attribute.IsCanonical());
+  ASSERT_EQ(is_web_bundle, link_rel_attribute.IsWebBundle());
 }
 
 TEST(LinkRelAttributeTest, Constructor) {
@@ -140,6 +142,12 @@
   TestLinkRelAttribute("caNONiCAL", false,
                        mojom::blink::FaviconIconType::kInvalid, false, false,
                        false, false, false, true);
+  TestLinkRelAttribute("webbundle", false,
+                       mojom::blink::FaviconIconType::kInvalid, false, false,
+                       false, false, false, false, true);
+  TestLinkRelAttribute("wEbBundle", false,
+                       mojom::blink::FaviconIconType::kInvalid, false, false,
+                       false, false, false, false, true);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/link_web_bundle.cc b/third_party/blink/renderer/core/html/link_web_bundle.cc
new file mode 100644
index 0000000..b70faeb8
--- /dev/null
+++ b/third_party/blink/renderer/core/html/link_web_bundle.cc
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/html/link_web_bundle.h"
+
+namespace blink {
+
+LinkWebBundle::LinkWebBundle(HTMLLinkElement* owner) : LinkResource(owner) {}
+
+void LinkWebBundle::Process() {
+  // TODO(crbug.com/1082020): Implement this.
+}
+
+LinkResource::LinkResourceType LinkWebBundle::GetType() const {
+  return kOther;
+}
+
+bool LinkWebBundle::HasLoaded() const {
+  return false;
+}
+
+void LinkWebBundle::OwnerRemoved() {}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/html/link_web_bundle.h b/third_party/blink/renderer/core/html/link_web_bundle.h
new file mode 100644
index 0000000..a21f27e
--- /dev/null
+++ b/third_party/blink/renderer/core/html/link_web_bundle.h
@@ -0,0 +1,28 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_LINK_WEB_BUNDLE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_LINK_WEB_BUNDLE_H_
+
+#include "third_party/blink/renderer/core/html/link_resource.h"
+
+namespace blink {
+
+// LinkWebBundle is used in the Subresource loading with Web Bundles feature.
+// See crbug.com/1082020 for details.
+// A <link rel="webbundle" ...> element creates LinkWebBundle.
+class LinkWebBundle final : public LinkResource {
+ public:
+  explicit LinkWebBundle(HTMLLinkElement* owner);
+  ~LinkWebBundle() override = default;
+
+  void Process() override;
+  LinkResourceType GetType() const override;
+  bool HasLoaded() const override;
+  void OwnerRemoved() override;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_LINK_WEB_BUNDLE_H_
diff --git a/third_party/blink/renderer/core/html/media/autoplay_policy.cc b/third_party/blink/renderer/core/html/media/autoplay_policy.cc
index bd1d889..c169dbcb 100644
--- a/third_party/blink/renderer/core/html/media/autoplay_policy.cc
+++ b/third_party/blink/renderer/core/html/media/autoplay_policy.cc
@@ -89,7 +89,8 @@
     return false;
 
   bool feature_policy_enabled =
-      document.IsFeatureEnabled(mojom::blink::FeaturePolicyFeature::kAutoplay);
+      document.GetExecutionContext()->IsFeatureEnabled(
+          mojom::blink::FeaturePolicyFeature::kAutoplay);
 
   for (Frame* frame = document.GetFrame(); frame;
        frame = frame->Tree().Parent()) {
@@ -361,11 +362,11 @@
 
   autoplay_initiated_ = true;
 
-  const Document& document = element_->GetDocument();
   bool feature_policy_enabled =
-      document.IsFeatureEnabled(mojom::blink::FeaturePolicyFeature::kAutoplay);
+      element_->GetExecutionContext()->IsFeatureEnabled(
+          mojom::blink::FeaturePolicyFeature::kAutoplay);
 
-  for (Frame* frame = document.GetFrame(); frame;
+  for (Frame* frame = element_->GetDocument().GetFrame(); frame;
        frame = frame->Tree().Parent()) {
     if (frame->HasStickyUserActivation() ||
         frame->HadStickyUserActivationBeforeNavigation()) {
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.cc b/third_party/blink/renderer/core/html/media/html_video_element.cc
index a76a839..591c343 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_video_element.cc
@@ -87,7 +87,7 @@
       is_effectively_fullscreen_(false),
       is_default_overridden_intrinsic_size_(
           !document.IsMediaDocument() &&
-          !document.IsFeatureEnabled(
+          !GetExecutionContext()->IsFeatureEnabled(
               mojom::blink::DocumentPolicyFeature::kUnsizedMedia)),
       video_has_played_(false),
       mostly_filling_viewport_(false) {
diff --git a/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc b/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc
index eb358a1..b358da20 100644
--- a/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc
+++ b/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc
@@ -18,7 +18,7 @@
   bool is_unsized = !style.LogicalWidth().IsSpecified() &&
                     !style.LogicalHeight().IsSpecified();
   if (is_unsized) {
-    layout_object->GetDocument().IsFeatureEnabled(
+    layout_object->GetDocument().GetExecutionContext()->IsFeatureEnabled(
         mojom::blink::DocumentPolicyFeature::kUnsizedMedia,
         send_report ? ReportOptions::kReportOnFailure
                     : ReportOptions::kDoNotReport);
diff --git a/third_party/blink/renderer/core/html/parser/html_resource_preloader.cc b/third_party/blink/renderer/core/html/parser/html_resource_preloader.cc
index cf00161..0dca628 100644
--- a/third_party/blink/renderer/core/html/parser/html_resource_preloader.cc
+++ b/third_party/blink/renderer/core/html/parser/html_resource_preloader.cc
@@ -122,8 +122,7 @@
     case ResourceType::kCSSStyleSheet:
       return true;
     case ResourceType::kFont:
-      return base::FeatureList::IsEnabled(
-          features::kLightweightNoStatePrefetch_FetchFonts);
+      return false;
     case ResourceType::kScript:
       // We might skip all script.
       if (GetFieldTrialParamByFeatureAsBool(
diff --git a/third_party/blink/renderer/core/html/rel_list.cc b/third_party/blink/renderer/core/html/rel_list.cc
index dc25711..ac9d32a 100644
--- a/third_party/blink/renderer/core/html/rel_list.cc
+++ b/third_party/blink/renderer/core/html/rel_list.cc
@@ -54,6 +54,11 @@
         token_value == "allowed-alt-sxg") {
       return true;
     }
+    if (RuntimeEnabledFeatures::SubresourceWebBundlesEnabled(
+            &GetElement().GetDocument()) &&
+        token_value == "webbundle") {
+      return true;
+    }
   } else if ((GetElement().HasTagName(html_names::kATag) ||
               GetElement().HasTagName(html_names::kAreaTag)) &&
              SupportedTokensAnchorAndArea().Contains(token_value)) {
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h b/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h
index 58c1010c..1babc40 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h
@@ -57,7 +57,7 @@
 class ExecutionContext;
 class ImageBitmapSource;
 
-class ImageBitmapFactories final
+class CORE_EXPORT ImageBitmapFactories final
     : public GarbageCollected<ImageBitmapFactories>,
       public Supplement<ExecutionContext>,
       public NameClient {
@@ -78,6 +78,11 @@
                                          int sh,
                                          const ImageBitmapOptions*,
                                          ExceptionState&);
+  static ScriptPromise CreateImageBitmap(ScriptState*,
+                                         ImageBitmapSource*,
+                                         base::Optional<IntRect> crop_rect,
+                                         const ImageBitmapOptions*,
+                                         ExceptionState&);
 
   virtual ~ImageBitmapFactories() = default;
 
@@ -144,11 +149,6 @@
   };
 
   static ImageBitmapFactories& From(ExecutionContext&);
-  static ScriptPromise CreateImageBitmap(ScriptState*,
-                                         ImageBitmapSource*,
-                                         base::Optional<IntRect> crop_rect,
-                                         const ImageBitmapOptions*,
-                                         ExceptionState&);
   static ScriptPromise CreateImageBitmapFromBlob(
       ScriptState*,
       ImageBitmapSource*,
diff --git a/third_party/blink/renderer/core/input/mouse_wheel_event_manager.cc b/third_party/blink/renderer/core/input/mouse_wheel_event_manager.cc
index eaf6ca7..3f55af5 100644
--- a/third_party/blink/renderer/core/input/mouse_wheel_event_manager.cc
+++ b/third_party/blink/renderer/core/input/mouse_wheel_event_manager.cc
@@ -15,6 +15,8 @@
 #include "third_party/blink/renderer/core/layout/hit_test_request.h"
 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/page/pointer_lock_controller.h"
 #include "third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h"
 #include "third_party/blink/renderer/core/page/scrolling/scroll_state.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
@@ -85,12 +87,18 @@
   bool has_phase_info = event.phase != WebMouseWheelEvent::kPhaseNone ||
                         event.momentum_phase != WebMouseWheelEvent::kPhaseNone;
 
-  // Find and save the wheel_target_, this target will be used for the rest
-  // of the current scrolling sequence. In the absence of phase info, send the
-  // event to the target under the cursor.
-  if (event.phase == WebMouseWheelEvent::kPhaseBegan || !wheel_target_ ||
-      !has_phase_info) {
-    wheel_target_ = FindTargetNode(event, doc, view);
+  Element* pointer_locked_element =
+      PointerLockController::GetPointerLockedElement(frame_);
+  if (pointer_locked_element) {
+    wheel_target_ = pointer_locked_element;
+  } else {
+    // Find and save the wheel_target_, this target will be used for the rest
+    // of the current scrolling sequence. In the absence of phase info, send the
+    // event to the target under the cursor.
+    if (event.phase == WebMouseWheelEvent::kPhaseBegan || !wheel_target_ ||
+        !has_phase_info) {
+      wheel_target_ = FindTargetNode(event, doc, view);
+    }
   }
 
   LocalFrame* subframe =
diff --git a/third_party/blink/renderer/core/input/pointer_event_manager.cc b/third_party/blink/renderer/core/input/pointer_event_manager.cc
index dabeef0..99b37de 100644
--- a/third_party/blink/renderer/core/input/pointer_event_manager.cc
+++ b/third_party/blink/renderer/core/input/pointer_event_manager.cc
@@ -61,14 +61,6 @@
   }
 }
 
-Element* GetPointerLockedElement(LocalFrame* frame) {
-  if (Page* p = frame->GetPage()) {
-    if (!p->GetPointerLockController().LockPending())
-      return p->GetPointerLockController().GetElement();
-  }
-  return nullptr;
-}
-
 }  // namespace
 
 PointerEventManager::PointerEventManager(LocalFrame& frame,
@@ -549,7 +541,8 @@
     // not quite possible as we haven't merged the locked event
     // dispatch with this path.
     Node* target;
-    Element* pointer_locked_element = GetPointerLockedElement(frame_);
+    Element* pointer_locked_element =
+        PointerLockController::GetPointerLockedElement(frame_);
     if (pointer_locked_element &&
         event.pointer_type == WebPointerProperties::PointerType::kMouse) {
       // The locked element could be in another frame. So we need to delegate
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
index 91792d6b..42dd8005 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -588,16 +588,17 @@
     return LayoutUnit();
   DCHECK_GE(percent_resolution_sizes.inline_size, 0);
   if (IsColumnFlow(style)) {
-    if (LIKELY(style.RowGap().IsNormal()))
-      return LayoutUnit();
-    return MinimumValueForLength(
-        style.RowGap().GetLength(),
-        percent_resolution_sizes.block_size.ClampNegativeToZero());
-  }
-  if (LIKELY(style.ColumnGap().IsNormal()))
+    if (const base::Optional<Length>& row_gap = style.RowGap()) {
+      return MinimumValueForLength(
+          *row_gap, percent_resolution_sizes.block_size.ClampNegativeToZero());
+    }
     return LayoutUnit();
-  return MinimumValueForLength(style.ColumnGap().GetLength(),
-                               percent_resolution_sizes.inline_size);
+  }
+  if (const base::Optional<Length>& column_gap = style.ColumnGap()) {
+    return MinimumValueForLength(*column_gap,
+                                 percent_resolution_sizes.inline_size);
+  }
+  return LayoutUnit();
 }
 
 // static
@@ -608,16 +609,17 @@
     return LayoutUnit();
   DCHECK_GE(percent_resolution_sizes.inline_size, 0);
   if (!IsColumnFlow(style)) {
-    if (LIKELY(style.RowGap().IsNormal()))
-      return LayoutUnit();
-    return MinimumValueForLength(
-        style.RowGap().GetLength(),
-        percent_resolution_sizes.block_size.ClampNegativeToZero());
-  }
-  if (LIKELY(style.ColumnGap().IsNormal()))
+    if (const base::Optional<Length>& row_gap = style.RowGap()) {
+      return MinimumValueForLength(
+          *row_gap, percent_resolution_sizes.block_size.ClampNegativeToZero());
+    }
     return LayoutUnit();
-  return MinimumValueForLength(style.ColumnGap().GetLength(),
-                               percent_resolution_sizes.inline_size);
+  }
+  if (const base::Optional<Length>& column_gap = style.ColumnGap()) {
+    return MinimumValueForLength(*column_gap,
+                                 percent_resolution_sizes.inline_size);
+  }
+  return LayoutUnit();
 }
 
 FlexLayoutAlgorithm::FlexLayoutAlgorithm(const ComputedStyle* style,
@@ -633,13 +635,13 @@
   DCHECK_GE(gap_between_lines_, 0);
   const auto& row_gap = style->RowGap();
   const auto& column_gap = style->ColumnGap();
-  if (!row_gap.IsNormal() || !column_gap.IsNormal()) {
+  if (row_gap || column_gap) {
     UseCounter::Count(document, WebFeature::kFlexGapSpecified);
     if (gap_between_items_ || gap_between_lines_)
       UseCounter::Count(document, WebFeature::kFlexGapPositive);
   }
 
-  if (!row_gap.IsNormal() && row_gap.GetLength().IsPercentOrCalc()) {
+  if (row_gap && row_gap->IsPercentOrCalc()) {
     UseCounter::Count(document, WebFeature::kFlexRowGapPercent);
     if (percent_resolution_sizes.block_size == LayoutUnit(-1))
       UseCounter::Count(document, WebFeature::kFlexRowGapPercentIndefinite);
diff --git a/third_party/blink/renderer/core/layout/geometry/logical_rect.cc b/third_party/blink/renderer/core/layout/geometry/logical_rect.cc
index 93912b4..a451057 100644
--- a/third_party/blink/renderer/core/layout/geometry/logical_rect.cc
+++ b/third_party/blink/renderer/core/layout/geometry/logical_rect.cc
@@ -40,21 +40,12 @@
 
 PhysicalRect LogicalRect::ConvertToPhysical(
     WritingMode writing_mode,
+    TextDirection direction,
     const PhysicalSize& outer_size) const {
-  if (IsHorizontalWritingMode(writing_mode)) {
-    return {offset.inline_offset, offset.block_offset, size.inline_size,
-            size.block_size};
-  }
-
-  // Vertical, clock-wise rotation.
-  if (writing_mode != WritingMode::kSidewaysLr) {
-    return {outer_size.width - BlockEndOffset(), offset.inline_offset,
-            size.block_size, size.inline_size};
-  }
-
-  // Vertical, counter-clock-wise rotation.
-  return {offset.block_offset, outer_size.height - InlineEndOffset(),
-          size.block_size, size.inline_size};
+  const PhysicalSize physical_size = ToPhysicalSize(size, writing_mode);
+  const PhysicalOffset physical_offset = offset.ConvertToPhysical(
+      writing_mode, direction, outer_size, physical_size);
+  return {physical_offset, physical_size};
 }
 
 String LogicalRect::ToString() const {
diff --git a/third_party/blink/renderer/core/layout/geometry/logical_rect.h b/third_party/blink/renderer/core/layout/geometry/logical_rect.h
index 43d65da..b391cd7 100644
--- a/third_party/blink/renderer/core/layout/geometry/logical_rect.h
+++ b/third_party/blink/renderer/core/layout/geometry/logical_rect.h
@@ -69,7 +69,11 @@
   void Unite(const LogicalRect&);
 
   // Convert logical coordinate to local physical coordinate.
+  // Note: When |LogicalRect| is constructed from |LayoutRect|, we should
+  // be careful about |direction|, because of |LayoutRect| may or may not
+  // ignore |TextDirection|.
   PhysicalRect ConvertToPhysical(WritingMode writing_mode,
+                                 TextDirection direction,
                                  const PhysicalSize& outer_size) const;
 
   String ToString() const;
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index 933313a..10f9c34d 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -308,10 +308,12 @@
 
   LayoutUnit MinimumLogicalHeightForEmptyLine() const {
     return BorderAndPaddingLogicalHeight() + ScrollbarLogicalHeight() +
-           LineHeight(
-               true,
-               IsHorizontalWritingMode() ? kHorizontalLine : kVerticalLine,
-               kPositionOfInteriorLineBoxes);
+           LogicalHeightForEmptyLine();
+  }
+  LayoutUnit LogicalHeightForEmptyLine() const {
+    return LineHeight(
+        true, IsHorizontalWritingMode() ? kHorizontalLine : kVerticalLine,
+        kPositionOfInteriorLineBoxes);
   }
 
   void SetLogicalLeft(LayoutUnit left) {
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_content.cc b/third_party/blink/renderer/core/layout/layout_embedded_content.cc
index 41b92eaa..f1b0f6c4 100644
--- a/third_party/blink/renderer/core/layout/layout_embedded_content.cc
+++ b/third_party/blink/renderer/core/layout/layout_embedded_content.cc
@@ -92,6 +92,14 @@
   return DynamicTo<FrameView>(GetEmbeddedContentView());
 }
 
+LayoutView* LayoutEmbeddedContent::ChildLayoutView() const {
+  if (HTMLFrameOwnerElement* owner_element = GetFrameOwnerElement()) {
+    if (Document* content_document = owner_element->contentDocument())
+      return content_document->GetLayoutView();
+  }
+  return nullptr;
+}
+
 WebPluginContainerImpl* LayoutEmbeddedContent::Plugin() const {
   EmbeddedContentView* embedded_content_view = GetEmbeddedContentView();
   if (embedded_content_view && embedded_content_view->IsPluginView())
@@ -106,44 +114,30 @@
 }
 
 PaintLayerType LayoutEmbeddedContent::LayerTypeRequired() const {
-  if (RequiresAcceleratedCompositing())
+  if (AdditionalCompositingReasons())
     return kNormalPaintLayer;
 
   PaintLayerType type = LayoutReplaced::LayerTypeRequired();
   if (type != kNoPaintLayer)
     return type;
-  return kForcedPaintLayer;
-}
 
-bool LayoutEmbeddedContent::RequiresAcceleratedCompositing() const {
-  // There are two general cases in which we can return true. First, if this is
-  // a plugin LayoutObject and the plugin has a layer, then we need a layer.
-  // Second, if this is a LayoutObject with a contentDocument and that document
-  // needs a layer, then we need a layer.
-  WebPluginContainerImpl* plugin_view = Plugin();
-  if (plugin_view && plugin_view->CcLayer())
-    return true;
-
-  auto* element = GetFrameOwnerElement();
-  if (!element)
-    return false;
-
-  if (Frame* content_frame = element->ContentFrame()) {
-    if (content_frame->IsRemoteFrame())
-      return true;
-    if (base::FeatureList::IsEnabled(
-            blink::features::kCompositeCrossOriginIframes) &&
-        content_frame->IsCrossOriginToParentFrame()) {
-      return true;
+  // We can't check layout_view->Layer()->GetCompositingReasons() here because
+  // we're only in style update, so haven't run compositing update yet.
+  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+    if (LayoutView* child_layout_view = ChildLayoutView()) {
+      if (child_layout_view->AdditionalCompositingReasons())
+        return kNormalPaintLayer;
     }
   }
 
-  if (Document* content_document = element->contentDocument()) {
-    auto* layout_view = content_document->GetLayoutView();
-    if (layout_view)
-      return layout_view->UsesCompositing();
-  }
+  return kForcedPaintLayer;
+}
 
+bool LayoutEmbeddedContent::ContentDocumentIsCompositing() const {
+  if (PaintLayerCompositor* inner_compositor =
+          PaintLayerCompositor::FrameContentsCompositor(*this)) {
+    return inner_compositor->StaleInCompositingMode();
+  }
   return false;
 }
 
@@ -253,8 +247,19 @@
 }
 
 CompositingReasons LayoutEmbeddedContent::AdditionalCompositingReasons() const {
-  if (RequiresAcceleratedCompositing())
-    return CompositingReason::kIFrame;
+  WebPluginContainerImpl* plugin_view = Plugin();
+  if (plugin_view && plugin_view->CcLayer())
+    return CompositingReason::kPlugin;
+  if (auto* element = GetFrameOwnerElement()) {
+    if (Frame* content_frame = element->ContentFrame()) {
+      if (content_frame->IsRemoteFrame() ||
+          (base::FeatureList::IsEnabled(
+               blink::features::kCompositeCrossOriginIframes) &&
+           content_frame->IsCrossOriginToParentFrame())) {
+        return CompositingReason::kIFrame;
+      }
+    }
+  }
   return CompositingReason::kNone;
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_content.h b/third_party/blink/renderer/core/layout/layout_embedded_content.h
index ce5d1ef..223f1a6 100644
--- a/third_party/blink/renderer/core/layout/layout_embedded_content.h
+++ b/third_party/blink/renderer/core/layout/layout_embedded_content.h
@@ -44,7 +44,7 @@
   explicit LayoutEmbeddedContent(HTMLFrameOwnerElement*);
   ~LayoutEmbeddedContent() override;
 
-  bool RequiresAcceleratedCompositing() const;
+  bool ContentDocumentIsCompositing() const;
 
   bool NodeAtPoint(HitTestResult&,
                    const HitTestLocation&,
@@ -59,6 +59,7 @@
   // to LayoutObject::GetFrameView which returns the LocalFrameView associated
   // with the root Document Frame.
   FrameView* ChildFrameView() const;
+  LayoutView* ChildLayoutView() const;
   WebPluginContainerImpl* Plugin() const;
   EmbeddedContentView* GetEmbeddedContentView() const;
 
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_object.cc b/third_party/blink/renderer/core/layout/layout_embedded_object.cc
index 6e40a3b1..913e462 100644
--- a/third_party/blink/renderer/core/layout/layout_embedded_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_embedded_object.cc
@@ -107,12 +107,6 @@
   ClearNeedsLayout();
 }
 
-CompositingReasons LayoutEmbeddedObject::AdditionalCompositingReasons() const {
-  if (RequiresAcceleratedCompositing())
-    return CompositingReason::kPlugin;
-  return CompositingReason::kNone;
-}
-
 void LayoutEmbeddedObject::ComputeIntrinsicSizingInfo(
     IntrinsicSizingInfo& intrinsic_sizing_info) const {
   DCHECK(!ShouldApplySizeContainment());
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_object.h b/third_party/blink/renderer/core/layout/layout_embedded_object.h
index 8aa0c87..8cc0293e 100644
--- a/third_party/blink/renderer/core/layout/layout_embedded_object.h
+++ b/third_party/blink/renderer/core/layout/layout_embedded_object.h
@@ -62,8 +62,6 @@
   void ComputeIntrinsicSizingInfo(IntrinsicSizingInfo&) const override;
   bool NeedsPreferredWidthsRecalculation() const override;
 
-  CompositingReasons AdditionalCompositingReasons() const override;
-
   PluginAvailability plugin_availability_ = kPluginAvailable;
   String unavailable_plugin_replacement_text_;
 };
diff --git a/third_party/blink/renderer/core/layout/layout_grid.cc b/third_party/blink/renderer/core/layout/layout_grid.cc
index d257d4a..6c53083 100644
--- a/third_party/blink/renderer/core/layout/layout_grid.cc
+++ b/third_party/blink/renderer/core/layout/layout_grid.cc
@@ -378,8 +378,8 @@
     LayoutGridItems();
     track_sizing_algorithm_.Reset();
 
-    if (NumTracks(kForRows, *grid_) > 1u && !StyleRef().RowGap().IsNormal() &&
-        StyleRef().RowGap().GetLength().IsPercentOrCalc()) {
+    if (NumTracks(kForRows, *grid_) > 1u && StyleRef().RowGap() &&
+        StyleRef().RowGap()->IsPercentOrCalc()) {
       UseCounter::Count(GetDocument(), WebFeature::kGridRowGapPercent);
       if (!CachedHasDefiniteLogicalHeight()) {
         UseCounter::Count(GetDocument(),
@@ -406,31 +406,31 @@
 LayoutUnit LayoutGrid::GridGap(
     GridTrackSizingDirection direction,
     base::Optional<LayoutUnit> available_size) const {
-  const GapLength& gap =
+  const base::Optional<Length>& gap =
       direction == kForColumns ? StyleRef().ColumnGap() : StyleRef().RowGap();
-  if (gap.IsNormal())
+  if (!gap)
     return LayoutUnit();
 
-  return ValueForLength(gap.GetLength(), available_size.value_or(LayoutUnit()));
+  return ValueForLength(*gap, available_size.value_or(LayoutUnit()));
 }
 
 LayoutUnit LayoutGrid::GridGap(GridTrackSizingDirection direction) const {
   LayoutUnit available_size;
   bool is_row_axis = direction == kForColumns;
 
-  const GapLength& gap =
+  const base::Optional<Length>& gap =
       is_row_axis ? StyleRef().ColumnGap() : StyleRef().RowGap();
-  if (gap.IsNormal())
+  if (!gap)
     return LayoutUnit();
 
-  if (gap.GetLength().IsPercentOrCalc()) {
+  if (gap->IsPercentOrCalc()) {
     available_size =
         is_row_axis ? AvailableLogicalWidth() : ContentLogicalHeight();
   }
 
   // TODO(rego): Maybe we could cache the computed percentage as a performance
   // improvement.
-  return ValueForLength(gap.GetLength(), available_size);
+  return ValueForLength(*gap, available_size);
 }
 
 LayoutUnit LayoutGrid::GuttersSize(
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc
index 46bb025..3e25c8e 100644
--- a/third_party/blink/renderer/core/layout/layout_inline.cc
+++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -470,8 +470,16 @@
   LayoutRect caret_rect =
       LocalCaretRectForEmptyElement(BorderAndPaddingWidth(), LayoutUnit());
 
-  if (InlineBox* first_box = FirstLineBox())
+  if (InlineBox* first_box = FirstLineBox()) {
     caret_rect.MoveBy(first_box->Location());
+  } else if (IsInLayoutNGInlineFormattingContext()) {
+    NGInlineCursor cursor;
+    cursor.MoveTo(*this);
+    if (cursor) {
+      caret_rect.MoveBy(
+          cursor.Current().OffsetInContainerBlock().ToLayoutPoint());
+    }
+  }
 
   return caret_rect;
 }
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
index c9bd201f..fee52b9 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
@@ -778,11 +778,11 @@
 
 LayoutUnit LayoutMultiColumnFlowThread::ColumnGap(const ComputedStyle& style,
                                                   LayoutUnit available_width) {
-  if (style.ColumnGap().IsNormal()) {
-    // "1em" is recommended as the normal gap setting. Matches <p> margins.
-    return LayoutUnit(style.GetFontDescription().ComputedSize());
-  }
-  return ValueForLength(style.ColumnGap().GetLength(), available_width);
+  if (const base::Optional<Length>& column_gap = style.ColumnGap())
+    return ValueForLength(*column_gap, available_width);
+
+  // "1em" is recommended as the normal gap setting. Matches <p> margins.
+  return LayoutUnit(style.GetFontDescription().ComputedSize());
 }
 
 void LayoutMultiColumnFlowThread::CreateAndInsertMultiColumnSet(
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_set.cc b/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
index 05575c7..5c1b833 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
@@ -488,13 +488,13 @@
 LayoutUnit LayoutMultiColumnSet::ColumnGap() const {
   LayoutBlockFlow* parent_block = MultiColumnBlockFlow();
 
-  if (parent_block->StyleRef().ColumnGap().IsNormal()) {
-    // "1em" is recommended as the normal gap setting. Matches <p> margins.
-    return LayoutUnit(
-        parent_block->StyleRef().GetFontDescription().ComputedPixelSize());
-  }
-  return ValueForLength(parent_block->StyleRef().ColumnGap().GetLength(),
-                        AvailableLogicalWidth());
+  if (const base::Optional<Length>& column_gap =
+          parent_block->StyleRef().ColumnGap())
+    return ValueForLength(*column_gap, AvailableLogicalWidth());
+
+  // "1em" is recommended as the normal gap setting. Matches <p> margins.
+  return LayoutUnit(
+      parent_block->StyleRef().GetFontDescription().ComputedPixelSize());
 }
 
 unsigned LayoutMultiColumnSet::ActualColumnCount() const {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_test.cc b/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_test.cc
index da28e31..9ee323b 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_test.cc
@@ -174,6 +174,38 @@
       GetItemsAsString(*text.GetLayoutObject()));
 }
 
+// editing/deleting/delete_ws_fixup.html
+TEST_F(LayoutNGTextTest, SetTextWithOffsetDeleteThenNonCollapse) {
+  if (!RuntimeEnabledFeatures::LayoutNGEnabled())
+    return;
+
+  SetBodyInnerHTML(u"<div id=target>abc def<b> </b>ghi</div>");
+  Text& text = To<Text>(*GetElementById("target")->firstChild());
+  text.deleteData(4, 3, ASSERT_NO_EXCEPTION);  // remove "def"
+
+  EXPECT_EQ(
+      "*{'abc ', ShapeResult=0+4}\n"
+      "{''}\n"
+      "{'ghi', ShapeResult=4+3}\n",
+      GetItemsAsString(*text.GetLayoutObject()));
+}
+
+// editing/deleting/delete_ws_fixup.html
+TEST_F(LayoutNGTextTest, SetTextWithOffsetDeleteThenNonCollapse2) {
+  if (!RuntimeEnabledFeatures::LayoutNGEnabled())
+    return;
+
+  SetBodyInnerHTML(u"<div id=target>abc def<b> X </b>ghi</div>");
+  Text& text = To<Text>(*GetElementById("target")->firstChild());
+  text.deleteData(4, 3, ASSERT_NO_EXCEPTION);  // remove "def"
+
+  EXPECT_EQ(
+      "*{'abc ', ShapeResult=0+4}\n"
+      "{'X ', ShapeResult=4+2}\n"
+      "{'ghi', ShapeResult=6+3}\n",
+      GetItemsAsString(*text.GetLayoutObject()));
+}
+
 // http://crbug.com/1039143
 TEST_F(LayoutNGTextTest, SetTextWithOffsetDeleteWithBidiControl) {
   if (!RuntimeEnabledFeatures::LayoutNGEnabled())
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
index 889eb939..b921de1 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
@@ -124,7 +124,6 @@
         box.metrics = box.text_metrics;
       else
         box.ResetTextMetrics();
-      box.has_annotation_overflow = false;
       if (box.has_start_edge) {
         // Existing box states are wrapped before they were closed, and hence
         // they do not have start edges, unless 'box-decoration-break: clone'.
@@ -235,10 +234,6 @@
     return;
   NGInlineBoxState& parent_box = *std::prev(box);
 
-  // Propagate necessary data back to the parent box.
-  parent_box.has_annotation_overflow =
-      parent_box.has_annotation_overflow || box->has_annotation_overflow;
-
   // Unite the metrics to the parent box.
   if (position_pending == kPositionNotPending)
     parent_box.metrics.Unite(box->metrics);
@@ -898,7 +893,6 @@
 
   DCHECK_EQ(metrics, other.metrics);
   DCHECK_EQ(text_metrics, other.text_metrics);
-  DCHECK_EQ(has_annotation_overflow, other.has_annotation_overflow);
   DCHECK_EQ(text_top, other.text_top);
   DCHECK_EQ(text_height, other.text_height);
   if (!text_metrics.IsEmpty()) {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
index d40bc21..6f58b80 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
@@ -50,9 +50,6 @@
   // by the 'line-height' property.
   NGLineHeightMetrics text_metrics;
 
-  // True if any boxes in the current line have non-zero annotation overflow.
-  bool has_annotation_overflow = false;
-
   // The distance between the text-top and the baseline for this box. The
   // text-top does not include leadings.
   LayoutUnit text_top;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
index 0ee94c9..515c372 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
@@ -655,6 +655,13 @@
                                        pixel_size);
 }
 
+PhysicalRect NGInlineCursorPosition::ConvertToPhysical(
+    const LogicalRect& logical_rect) const {
+  return logical_rect.ConvertToPhysical(
+      Style().GetWritingMode(),
+      IsLineBox() ? BaseDirection() : ResolvedDirection(), Size());
+}
+
 PositionWithAffinity NGInlineCursor::PositionForPointInInlineFormattingContext(
     const PhysicalOffset& point,
     const NGPhysicalBoxFragment& container) {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h
index 4f547ae..3041fcf 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h
@@ -170,6 +170,9 @@
   PhysicalOffset LineStartPoint() const;
   PhysicalOffset LineEndPoint() const;
 
+  // LogicalRect/PhysicalRect conversions
+  PhysicalRect ConvertToPhysical(const LogicalRect& logical_rect) const;
+
  private:
   void Set(const ItemsSpan::iterator& iter) {
     DCHECK(!paint_fragment_);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
index 6e66ff04..dca11ac 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
@@ -894,6 +894,7 @@
   RestoreTrailingCollapsibleSpaceIfRemoved();
   Append(NGInlineItem::kAtomicInline, kObjectReplacementCharacter,
          layout_object);
+  has_ruby_ = layout_object->IsRubyRun();
 
   // When this atomic inline is inside of an inline box, the height of the
   // inline box can be different from the height of the atomic inline. Ensure
@@ -1226,6 +1227,7 @@
   // |SegmentText()| will analyze the text and reset |is_bidi_enabled_| if it
   // doesn't contain any RTL characters.
   data->is_bidi_enabled_ = MayBeBidiEnabled();
+  data->has_ruby_ = has_ruby_;
   data->is_empty_inline_ = IsEmptyInline();
   data->is_block_level_ = IsBlockLevel();
   data->changes_may_affect_earlier_lines_ = ChangesMayAffectEarlierLines();
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
index a8e6d3f..6b60ccaa 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
@@ -177,6 +177,7 @@
   Vector<BidiContext> bidi_context_;
 
   bool has_bidi_controls_ = false;
+  bool has_ruby_ = false;
   bool is_empty_inline_ = true;
   bool is_block_level_ = true;
   bool changes_may_affect_earlier_lines_ = false;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index 083c052..5ff9494 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -381,7 +381,7 @@
   }
 
   NGLineHeightMetrics annotation_metrics = NGLineHeightMetrics::Zero();
-  if (box_states_->LineBoxState().has_annotation_overflow &&
+  if (Node().HasRuby() &&
       !RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
     annotation_metrics = ComputeAnnotationOverflow(
         line_box_metrics, -line_box_metrics.ascent, line_info->LineStyle());
@@ -415,7 +415,7 @@
   // the line box to the line top.
   line_box_.MoveInBlockDirection(line_box_metrics.ascent);
 
-  if (box_states_->LineBoxState().has_annotation_overflow &&
+  if (Node().HasRuby() &&
       RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
     annotation_metrics = ComputeAnnotationOverflow(
         line_box_metrics, LayoutUnit(), line_info->LineStyle());
@@ -436,7 +436,7 @@
     const NGLineHeightMetrics& line_box_metrics,
     LayoutUnit line_block_start,
     const ComputedStyle& line_style) {
-  DCHECK(box_states_->LineBoxState().has_annotation_overflow);
+  DCHECK(Node().HasRuby());
   DCHECK(RuntimeEnabledFeatures::LayoutNGRubyEnabled());
   LayoutUnit annotatin_block_start = line_block_start;
   const LayoutUnit line_block_end =
@@ -567,12 +567,8 @@
                     To<NGPhysicalBoxFragment>(
                         item_result->layout_result->PhysicalFragment()))
           .BaselineMetrics(item_result->margins, baseline_type_);
-  if (box) {
+  if (box)
     box->metrics.Unite(metrics);
-    box->has_annotation_overflow =
-        box->has_annotation_overflow ||
-        item_result->layout_result->AnnotationOverflow() != LayoutUnit();
-  }
 
   LayoutUnit line_top = item_result->margins.line_over - metrics.ascent;
   line_box_.AddChild(std::move(item_result->layout_result),
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index 4af5e23..d24eab0d 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -516,16 +516,19 @@
     // Skip items in replaced range.
     while (it->end_offset_ < end_offset)
       ++it;
-    DCHECK_EQ(it->layout_object_, layout_text_);
 
     // Inserted text
-    if (inserted_text_length > 0) {
-      const unsigned inserted_start_offset =
-          items.IsEmpty() ? 0 : items.back().end_offset_;
-      const unsigned inserted_end_offset =
-          inserted_start_offset + inserted_text_length;
-      items.push_back(NGInlineItem(*it, inserted_start_offset,
-                                   inserted_end_offset, nullptr));
+    if (it->layout_object_ == layout_text_) {
+      if (inserted_text_length > 0) {
+        const unsigned inserted_start_offset =
+            items.IsEmpty() ? 0 : items.back().end_offset_;
+        const unsigned inserted_end_offset =
+            inserted_start_offset + inserted_text_length;
+        items.push_back(NGInlineItem(*it, inserted_start_offset,
+                                     inserted_end_offset, nullptr));
+      }
+    } else {
+      DCHECK_LE(inserted_text_length, 0);
     }
 
     // Copy part of item after replaced range.
@@ -571,7 +574,6 @@
                              unsigned start_offset) const {
     DCHECK_LE(item.start_offset_, start_offset);
     DCHECK_LT(start_offset, item.end_offset_);
-    DCHECK_EQ(item.layout_object_, layout_text_);
     if (item.start_offset_ == start_offset)
       return item;
     const unsigned end_offset = item.end_offset_;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
index 2d318aeca..f99e978 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
@@ -108,6 +108,8 @@
   bool IsBidiEnabled() const { return Data().is_bidi_enabled_; }
   TextDirection BaseDirection() const { return Data().BaseDirection(); }
 
+  bool HasRuby() const { return Data().has_ruby_; }
+
   bool IsEmptyInline() { return EnsureData().is_empty_inline_; }
 
   bool IsBlockLevel() { return EnsureData().is_block_level_; }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
index 5dda66c..0f5fdd6 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
@@ -22,6 +22,8 @@
     return static_cast<TextDirection>(base_direction_);
   }
 
+  bool HasRuby() const { return has_ruby_; }
+
   bool IsEmptyInline() const { return is_empty_inline_; }
 
   bool IsBlockLevel() const { return is_block_level_; }
@@ -56,6 +58,9 @@
   unsigned is_bidi_enabled_ : 1;
   unsigned base_direction_ : 1;  // TextDirection
 
+  // The node contains <ruby>.
+  unsigned has_ruby_ : 1;
+
   // We use this flag to determine if the inline node is empty, and will
   // produce a single zero block-size line box. If the node has text, atomic
   // inlines, open/close tags with margins/border/padding this will be false.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc
index e5ed5b1..e06a8c9 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc
@@ -58,7 +58,8 @@
   }
 
   PhysicalRect local_ink_overflow =
-      LogicalRect(ink_overflow).ConvertToPhysical(writing_mode, size);
+      LogicalRect(ink_overflow)
+          .ConvertToPhysical(writing_mode, TextDirection::kLtr, size);
 
   // Uniting the frame rect ensures that non-ink spaces such side bearings, or
   // even space characters, are included in the visual rect for decorations.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
index a280e47..68eef7a 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
@@ -781,9 +781,9 @@
 
 LayoutUnit ResolveUsedColumnGap(LayoutUnit available_size,
                                 const ComputedStyle& style) {
-  if (style.ColumnGap().IsNormal())
-    return LayoutUnit(style.GetFontDescription().ComputedPixelSize());
-  return ValueForLength(style.ColumnGap().GetLength(), available_size);
+  if (const base::Optional<Length>& column_gap = style.ColumnGap())
+    return ValueForLength(*column_gap, available_size);
+  return LayoutUnit(style.GetFontDescription().ComputedPixelSize());
 }
 
 NGPhysicalBoxStrut ComputePhysicalMargins(
diff --git a/third_party/blink/renderer/core/layout/scroll_anchor_test.cc b/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
index 02472dc..d5028bd 100644
--- a/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
+++ b/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
@@ -1131,19 +1131,19 @@
     test::RunPendingTasks();
   }
 
-  mojom::blink::FindOptionsPtr FindOptions(bool find_next = false) {
+  mojom::blink::FindOptionsPtr FindOptions(bool new_session = true) {
     auto find_options = mojom::blink::FindOptions::New();
     find_options->run_synchronously_for_testing = true;
-    find_options->find_next = find_next;
+    find_options->new_session = new_session;
     find_options->forward = true;
     return find_options;
   }
 
   void Find(String search_text,
             ScrollAnchorTestFindInPageClient& client,
-            bool find_next = false) {
+            bool new_session = true) {
     client.Reset();
-    GetFindInPage()->Find(FAKE_FIND_ID, search_text, FindOptions(find_next));
+    GetFindInPage()->Find(FAKE_FIND_ID, search_text, FindOptions(new_session));
     test::RunPendingTasks();
   }
 
diff --git a/third_party/blink/renderer/core/loader/document_loader_test.cc b/third_party/blink/renderer/core/loader/document_loader_test.cc
index c680b907..d359aa8 100644
--- a/third_party/blink/renderer/core/loader/document_loader_test.cc
+++ b/third_party/blink/renderer/core/loader/document_loader_test.cc
@@ -255,9 +255,9 @@
   iframe_resource.Finish();
 
   auto* child_frame = To<WebLocalFrameImpl>(MainFrame().FirstChild());
-  auto* child_document = child_frame->GetFrame()->GetDocument();
+  auto* child_window = child_frame->GetFrame()->DomWindow();
 
-  EXPECT_TRUE(child_document->IsFeatureEnabled(
+  EXPECT_TRUE(child_window->IsFeatureEnabled(
       blink::mojom::blink::FeaturePolicyFeature::kPayment));
 }
 // When runtime feature DocumentPolicy is not enabled, specifying
@@ -286,7 +286,7 @@
 
   iframe_resource.Finish();
   auto* child_frame = To<WebLocalFrameImpl>(MainFrame().FirstChild());
-  auto* child_document = child_frame->GetFrame()->GetDocument();
+  auto* child_window = child_frame->GetFrame()->DomWindow();
   auto& console_messages = static_cast<frame_test_helpers::TestWebFrameClient*>(
                                child_frame->Client())
                                ->ConsoleMessages();
@@ -295,24 +295,24 @@
   // violation blocking document load.
   EXPECT_TRUE(console_messages.IsEmpty());
 
-  EXPECT_EQ(child_document->Url(), KURL("https://example.com/foo.html"));
+  EXPECT_EQ(child_window->Url(), KURL("https://example.com/foo.html"));
 
-  EXPECT_FALSE(child_document->IsUseCounted(
+  EXPECT_FALSE(child_window->document()->IsUseCounted(
       mojom::WebFeature::kDocumentPolicyCausedPageUnload));
 
   // Unoptimized-lossless-images should still be allowed in main document.
-  EXPECT_TRUE(GetDocument().IsFeatureEnabled(
+  EXPECT_TRUE(Window().IsFeatureEnabled(
       mojom::blink::DocumentPolicyFeature::kUnoptimizedLosslessImages,
       PolicyValue(2.0)));
-  EXPECT_TRUE(GetDocument().IsFeatureEnabled(
+  EXPECT_TRUE(Window().IsFeatureEnabled(
       mojom::blink::DocumentPolicyFeature::kUnoptimizedLosslessImages,
       PolicyValue(1.0)));
 
   // Unoptimized-lossless-images should still be allowed in child document.
-  EXPECT_TRUE(child_document->IsFeatureEnabled(
+  EXPECT_TRUE(child_window->IsFeatureEnabled(
       mojom::blink::DocumentPolicyFeature::kUnoptimizedLosslessImages,
       PolicyValue(2.0)));
-  EXPECT_TRUE(child_document->IsFeatureEnabled(
+  EXPECT_TRUE(child_window->IsFeatureEnabled(
       mojom::blink::DocumentPolicyFeature::kUnoptimizedLosslessImages,
       PolicyValue(1.0)));
 }
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index efcb6e2..1a357cc 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -1038,7 +1038,7 @@
   if (url.GetPath() != kWellKnownConversionRegsitrationPath)
     return false;
 
-  if (!document_->IsFeatureEnabled(
+  if (!document_->domWindow()->IsFeatureEnabled(
           mojom::blink::FeaturePolicyFeature::kConversionMeasurement)) {
     String message =
         "The 'conversion-measurement' feature policy must be enabled to "
diff --git a/third_party/blink/renderer/core/loader/image_loader.cc b/third_party/blink/renderer/core/loader/image_loader.cc
index 183f44b..bd24019 100644
--- a/third_party/blink/renderer/core/loader/image_loader.cc
+++ b/third_party/blink/renderer/core/loader/image_loader.cc
@@ -534,10 +534,8 @@
     ConfigureRequest(params, bypass_behavior, *element_,
                      document.GetFrame()->GetClientHintsPreferences());
 
-    if ((update_behavior != kUpdateForcedReload &&
-         lazy_image_load_state_ == LazyImageLoadState::kNone) ||
-        (update_behavior == kUpdateSizeChanged &&
-         lazy_image_load_state_ == LazyImageLoadState::kDeferred)) {
+    if (update_behavior != kUpdateForcedReload &&
+        lazy_image_load_state_ != LazyImageLoadState::kFullImage) {
       const auto* frame = document.GetFrame();
       if (auto* html_image = DynamicTo<HTMLImageElement>(GetElement())) {
         LoadingAttributeValue loading_attr = GetLoadingAttributeValue(
diff --git a/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc b/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc
index dbfcd9f..5604778 100644
--- a/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc
+++ b/third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.h"
 
+#include <utility>
+
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
@@ -300,16 +302,13 @@
       continue;
     auto* prefetched_exchange = maching_prefetched_exchanges.at(i);
     mojo::Remote<network::mojom::blink::URLLoaderFactory> loader_factory(
-        mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>(
-            std::move(prefetched_exchange->loader_factory_handle),
-            network::mojom::URLLoaderFactory::Version_));
+        std::move(prefetched_exchange->loader_factory));
     mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>
         loader_factory_clone;
     loader_factory->Clone(
         loader_factory_clone.InitWithNewPipeAndPassReceiver());
     // Reset loader_factory_handle to support loading the same resource again.
-    prefetched_exchange->loader_factory_handle =
-        loader_factory_clone.PassPipe();
+    prefetched_exchange->loader_factory = std::move(loader_factory_clone);
     loader->SetURLLoader(CreatePrefetchedSignedExchangeURLLoader(
         loader->request(), loader_factory.Unbind()));
   }
diff --git a/third_party/blink/renderer/core/page/pointer_lock_controller.cc b/third_party/blink/renderer/core/page/pointer_lock_controller.cc
index b7139ac8..c37f214 100644
--- a/third_party/blink/renderer/core/page/pointer_lock_controller.cc
+++ b/third_party/blink/renderer/core/page/pointer_lock_controller.cc
@@ -340,4 +340,13 @@
   visitor->Trace(document_of_removed_element_while_waiting_for_unlock_);
 }
 
+// static
+Element* PointerLockController::GetPointerLockedElement(LocalFrame* frame) {
+  if (Page* p = frame->GetPage()) {
+    if (!p->GetPointerLockController().LockPending())
+      return p->GetPointerLockController().GetElement();
+  }
+  return nullptr;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/pointer_lock_controller.h b/third_party/blink/renderer/core/page/pointer_lock_controller.h
index 4e1a87f..30cc549 100644
--- a/third_party/blink/renderer/core/page/pointer_lock_controller.h
+++ b/third_party/blink/renderer/core/page/pointer_lock_controller.h
@@ -76,6 +76,8 @@
                               FloatPoint* lock_screen_position);
   void Trace(Visitor*) const;
 
+  static Element* GetPointerLockedElement(LocalFrame* frame);
+
  private:
   void ClearElement();
   void EnqueueEvent(const AtomicString& type, Element*);
diff --git a/third_party/blink/renderer/core/page/zoom_test.cc b/third_party/blink/renderer/core/page/zoom_test.cc
deleted file mode 100644
index 487d9586..0000000
--- a/third_party/blink/renderer/core/page/zoom_test.cc
+++ /dev/null
@@ -1,30 +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 "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
-
-namespace blink {
-
-class FractionalZoomSimTest : public SimTest {};
-
-TEST_F(FractionalZoomSimTest, CheckCSSMediaQueryWidthEqualsWindowInnerWidth) {
-  WebView().MainFrameWidget()->Resize(WebSize(1081, 1921));
-
-  // 1081/2.75 = 393.091
-  // 1081/2.00 = 540.500
-  // 1081/1.50 = 720.667
-  std::vector<float> factors = {2.75f, 2.00f, 1.50f};
-  for (auto factor : factors) {
-    WebView().SetZoomFactorForDeviceScaleFactor(factor);
-    EXPECT_EQ(GetDocument().View()->ViewportSizeForMediaQueries().Width(),
-              GetDocument().GetFrame()->DomWindow()->innerWidth());
-  }
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/background_image_geometry.cc b/third_party/blink/renderer/core/paint/background_image_geometry.cc
index deb215a..6920506b 100644
--- a/third_party/blink/renderer/core/paint/background_image_geometry.cc
+++ b/third_party/blink/renderer/core/paint/background_image_geometry.cc
@@ -89,16 +89,10 @@
   }
 
   if (x_offset > 0) {
-    DCHECK(snapped_x_offset >= LayoutUnit());
     // Move the dest rect if the offset is positive. The image "stays" where
     // it is over the dest rect, so this effectively modifies the phase.
     unsnapped_dest_rect_.Move(x_offset, LayoutUnit());
-
-    // For the snapped geometry, note that negative x_offsets typically
-    // arise when using positive offsets from the bottom of the background
-    // rect. We try to move the snapped dest rect to give the same offset.
-    LayoutUnit dx = snapped_dest_rect_.Width() - unsnapped_dest_rect_.Width();
-    snapped_dest_rect_.Move(x_offset + dx, LayoutUnit());
+    snapped_dest_rect_.SetX(LayoutUnit(unsnapped_dest_rect_.X().Round()));
 
     // Make the dest as wide as a tile, which will reduce the dest
     // rect if the tile is too small to fill the paint_rect. If not,
@@ -134,17 +128,12 @@
         LayoutSize(SpaceSize().Width(), unsnapped_dest_rect_.Height()));
     return;
   }
+
   if (y_offset > 0) {
-    DCHECK(snapped_y_offset >= LayoutUnit());
     // Move the dest rect if the offset is positive. The image "stays" where
     // it is in the paint rect, so this effectively modifies the phase.
     unsnapped_dest_rect_.Move(LayoutUnit(), y_offset);
-
-    // For the snapped geometry, note that negative y_offsets typically
-    // arise when using positive offsets from the bottom of the background
-    // rect. We try to move the snapped dest rect to give the same offset.
-    LayoutUnit dy = snapped_dest_rect_.Height() - unsnapped_dest_rect_.Height();
-    snapped_dest_rect_.Move(LayoutUnit(), y_offset + dy);
+    snapped_dest_rect_.SetY(LayoutUnit(unsnapped_dest_rect_.Y().Round()));
 
     // Make the dest as wide as a tile, which will reduce the dest
     // rect if the tile is too small to fill the paint_rect. If not,
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index abf0048..03bfd81 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -447,11 +447,6 @@
         graphics_layer_->SetContentsToCcLayer(
             remote->GetCcLayer(), remote->WebLayerHasFixedContentsOpaque());
       }
-      PaintLayerCompositor* inner_compositor =
-          PaintLayerCompositor::FrameContentsCompositor(
-              ToLayoutEmbeddedContent(layout_object));
-      if (inner_compositor && inner_compositor->RootLayerAttachmentDirty())
-        layer_config_changed = true;
     }
   } else if (IsA<LayoutVideo>(layout_object)) {
     auto* media_element = To<HTMLMediaElement>(layout_object.GetNode());
@@ -1423,7 +1418,7 @@
 
 static bool IsCompositedPlugin(LayoutObject& layout_object) {
   return layout_object.IsEmbeddedObject() &&
-         ToLayoutEmbeddedObject(layout_object).RequiresAcceleratedCompositing();
+         layout_object.AdditionalCompositingReasons();
 }
 
 bool CompositedLayerMapping::HasVisibleNonCompositingDescendant(
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc
index 90a9899..cabdc25 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/layout/layout_block.h"
+#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
@@ -189,6 +190,13 @@
     descendant_has_direct_compositing_reason |=
         LayerOrDescendantShouldBeComposited(child);
   }
+  if (!descendant_has_direct_compositing_reason &&
+      layer->GetLayoutObject().IsLayoutEmbeddedContent()) {
+    if (ToLayoutEmbeddedContent(layer->GetLayoutObject())
+            .ContentDocumentIsCompositing()) {
+      descendant_has_direct_compositing_reason = true;
+    }
+  }
   layer->SetDescendantHasDirectOrScrollingCompositingReason(
       descendant_has_direct_compositing_reason);
 
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
index 69468c5..8dcbfbc 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
@@ -376,11 +376,22 @@
   RecursionData child_recursion_data = current_recursion_data;
   child_recursion_data.subtree_is_compositing_ = false;
 
+  // Embedded objects treat the embedded document as a child for the purposes
+  // of composited layer decisions. Look into the embedded document to determine
+  // if it is composited.
+  bool contains_composited_layer =
+      (layer->GetLayoutObject().IsLayoutEmbeddedContent() &&
+       ToLayoutEmbeddedContent(layer->GetLayoutObject())
+           .ContentDocumentIsCompositing());
+
   bool will_be_composited_or_squashed =
       can_be_composited && RequiresCompositingOrSquashing(reasons_to_composite);
-  if (will_be_composited_or_squashed) {
-    // This layer now acts as the ancestor for child layers.
-    child_recursion_data.compositing_ancestor_ = layer;
+
+  if (will_be_composited_or_squashed || contains_composited_layer) {
+    if (will_be_composited_or_squashed) {
+      // This layer now acts as the ancestor for child layers.
+      child_recursion_data.compositing_ancestor_ = layer;
+    }
 
     // Here we know that all children and the layer's own contents can blindly
     // paint into this layer's backing, until a descendant is composited. So, we
@@ -508,23 +519,15 @@
         child_recursion_data.has_unisolated_composited_blending_descendant_;
   }
 
-  // Embedded objects treat the embedded document as a child for the purposes
-  // of composited layer decisions. Look into the embedded document to determine
-  // if it is composited.
-  bool contains_composited_iframe =
-      layer->GetLayoutObject().IsLayoutEmbeddedContent() &&
-      ToLayoutEmbeddedContent(layer->GetLayoutObject())
-          .RequiresAcceleratedCompositing();
-
   // Subsequent layers in the parent's stacking context may also need to
   // composite.
-  if (child_recursion_data.subtree_is_compositing_)
+  if (child_recursion_data.subtree_is_compositing_ || contains_composited_layer)
     current_recursion_data.subtree_is_compositing_ = true;
 
   // Set the flag to say that this SC has compositing children.
   layer->SetHasCompositingDescendant(
       child_recursion_data.subtree_is_compositing_ ||
-      contains_composited_iframe);
+      contains_composited_layer);
 
   if (layer->IsRootLayer()) {
     // The root layer needs to be composited if anything else in the tree is
@@ -550,9 +553,11 @@
     // the overlap map. Layers that are not separately composited will paint
     // into their compositing ancestor's backing, and so are still considered
     // for overlap.
-    if (child_recursion_data.compositing_ancestor_ &&
-        !child_recursion_data.compositing_ancestor_->IsRootLayer())
+    if ((child_recursion_data.compositing_ancestor_ &&
+         !child_recursion_data.compositing_ancestor_->IsRootLayer()) ||
+        contains_composited_layer) {
       overlap_map.Add(layer, abs_bounds, use_clipped_bounding_rect);
+    }
 
     // Now check for reasons to become composited that depend on the state of
     // descendant layers.
@@ -597,8 +602,10 @@
         layer->GetLayoutObject().StyleRef().HasCurrentTransformAnimation())
       current_recursion_data.testing_overlap_ = false;
 
-    if (child_recursion_data.compositing_ancestor_ == layer)
+    if (child_recursion_data.compositing_ancestor_ == layer ||
+        contains_composited_layer) {
       overlap_map.FinishCurrentOverlapTestingContext();
+    }
 
     descendant_has3d_transform |=
         any_descendant_has3d_transform || layer->Has3DTransform();
diff --git a/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc b/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc
index de0794d..344fc77 100644
--- a/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc
@@ -121,11 +121,12 @@
     PaintLayerCompositor* inner_compositor =
         PaintLayerCompositor::FrameContentsCompositor(
             ToLayoutEmbeddedContent(layer.GetLayoutObject()));
-    // If the embedded frame is render-throttled, it might not be compositing
-    // clean at this point. In that case, we still need to connect its existing
-    // root graphics layer, so we need to query the stale compositing state.
-    DisableCompositingQueryAsserts disabler;
     if (inner_compositor) {
+      // If the embedded frame is render-throttled, it might not be compositing
+      // clean at this point. In that case, we still need to connect its
+      // existing root graphics layer, so we need to query the stale compositing
+      // state.
+      DisableCompositingQueryAsserts disabler;
       if (inner_compositor->InCompositingMode()) {
         GraphicsLayer* inner_root_layer = inner_compositor->RootGraphicsLayer();
         DCHECK(inner_root_layer);
diff --git a/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.cc b/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.cc
index 6429266a..7683733 100644
--- a/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.cc
+++ b/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.cc
@@ -28,6 +28,7 @@
 
 #include "third_party/blink/renderer/core/html/media/html_media_element.h"
 #include "third_party/blink/renderer/core/layout/layout_block.h"
+#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
 #include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
@@ -140,6 +141,15 @@
     }
   }
 
+  if (layer.GetLayoutObject().IsLayoutEmbeddedContent()) {
+    if (PaintLayerCompositor* inner_compositor =
+            PaintLayerCompositor::FrameContentsCompositor(
+                ToLayoutEmbeddedContent(layer.GetLayoutObject()))) {
+      if (inner_compositor->RootLayerAttachmentDirty())
+        needs_rebuild_tree_ = true;
+    }
+  }
+
   PaintLayer* first_child =
       layer.GetLayoutObject().PrePaintBlockedByDisplayLock(
           DisplayLockLifecycleTarget::kChildren)
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
index 891f0e5..f09f2b9e 100644
--- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
+++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
@@ -92,10 +92,6 @@
   if (enable == compositing_)
     return;
   compositing_ = enable;
-  root_layer_attachment_dirty_ = true;
-  // Schedule an update in the parent frame so the <iframe>'s layer in the owner
-  // document matches the compositing state here.
-  SetOwnerNeedsCompositingUpdate();
 }
 
 void PaintLayerCompositor::UpdateAcceleratedCompositingSettings() {
@@ -399,11 +395,10 @@
     if (!child_list.IsEmpty()) {
       CHECK(compositing_);
       DCHECK_EQ(1u, child_list.size());
-      // If this is a popup, don't hook into the layer tree.
-      if (layout_view_.GetDocument().GetPage()->GetChromeClient().IsPopup())
-        current_parent = nullptr;
-      if (current_parent)
-        current_parent->SetChildren(child_list);
+      // Schedule an update in the parent frame so the <iframe>'s layer in the
+      // owner document matches the compositing state here.
+      SetOwnerNeedsCompositingUpdate();
+      root_layer_attachment_dirty_ = true;
     }
   }
 
@@ -512,8 +507,9 @@
 }
 
 PaintLayerCompositor* PaintLayerCompositor::FrameContentsCompositor(
-    LayoutEmbeddedContent& layout_object) {
-  auto* element = DynamicTo<HTMLFrameOwnerElement>(layout_object.GetNode());
+    const LayoutEmbeddedContent& layout_object) {
+  const auto* element =
+      DynamicTo<HTMLFrameOwnerElement>(layout_object.GetNode());
   if (!element)
     return nullptr;
 
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
index 6b2490c7..cbcab7f 100644
--- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
+++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
@@ -119,7 +119,8 @@
   // swapped out for an overlay video or immersive-ar DOM overlay layer.
   GraphicsLayer* PaintRootGraphicsLayer() const;
 
-  static PaintLayerCompositor* FrameContentsCompositor(LayoutEmbeddedContent&);
+  static PaintLayerCompositor* FrameContentsCompositor(
+      const LayoutEmbeddedContent&);
 
   void UpdateTrackingRasterInvalidations();
 
diff --git a/third_party/blink/renderer/core/paint/image_painter.cc b/third_party/blink/renderer/core/paint/image_painter.cc
index 6436abe..036cff6 100644
--- a/third_party/blink/renderer/core/paint/image_painter.cc
+++ b/third_party/blink/renderer/core/paint/image_painter.cc
@@ -9,6 +9,7 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/html/html_area_element.h"
 #include "third_party/blink/renderer/core/html/html_image_element.h"
@@ -60,7 +61,7 @@
   const String& image_url =
       cached_image ? cached_image->Url().GetString() : g_empty_string;
 
-  return !layout_image.GetDocument().IsFeatureEnabled(
+  return !layout_image.GetDocument().domWindow()->IsFeatureEnabled(
       mojom::blink::DocumentPolicyFeature::kOversizedImages,
       blink::PolicyValue(
           std::max(downscale_ratio_width, downscale_ratio_height),
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index 788f2d9..438e919 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -687,7 +687,17 @@
     if (box_child_fragment.IsColumnBox())
       continue;
 
-    child_fragment.GetLayoutObject()->Paint(paint_info_for_descendants);
+    auto* layout_object = child_fragment.GetLayoutObject();
+    DCHECK(layout_object);
+    if (child_fragment.IsPaintedAtomically() &&
+        child_fragment.IsLegacyLayoutRoot()) {
+      ObjectPainter(*layout_object)
+          .PaintAllPhasesAtomically(paint_info_for_descendants);
+    } else {
+      // TODO(ikilpatrick): Once FragmentItem ships we should call the
+      // NGBoxFragmentPainter directly for NG objects.
+      layout_object->Paint(paint_info_for_descendants);
+    }
   }
 }
 
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
index 4a50e2d..f0aa6d3 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -75,34 +75,6 @@
                                item.ResolvedDirection(), item.Size());
 }
 
-PhysicalRect ComputePhysicalRectFor(const LogicalRect& logical_rect,
-                                    WritingMode writing_mode,
-                                    TextDirection text_direction,
-                                    const PhysicalSize& outer_size) {
-  const PhysicalSize physical_size =
-      ToPhysicalSize(logical_rect.size, writing_mode);
-  const PhysicalOffset physical_offset = logical_rect.offset.ConvertToPhysical(
-      writing_mode, text_direction, outer_size, physical_size);
-
-  return {physical_offset, physical_size};
-}
-PhysicalRect ComputePhysicalRectFor(const LogicalRect& logical_rect,
-                                    const NGPaintFragment& paint_fragment) {
-  return ComputePhysicalRectFor(
-      logical_rect, paint_fragment.Style().GetWritingMode(),
-      paint_fragment.PhysicalFragment().ResolvedDirection(),
-      paint_fragment.Size());
-}
-
-PhysicalRect ComputePhysicalRectFor(const LogicalRect& logical_rect,
-                                    const NGInlineCursor& cursor) {
-  if (const NGPaintFragment* paint_fragment = cursor.CurrentPaintFragment())
-    return ComputePhysicalRectFor(logical_rect, *paint_fragment);
-  const NGFragmentItem& item = *cursor.CurrentItem();
-  return ComputePhysicalRectFor(logical_rect, item.GetWritingMode(),
-                                item.ResolvedDirection(), item.Size());
-}
-
 LogicalRect ExpandedSelectionRectForSoftLineBreakIfNeeded(
     const LogicalRect& rect,
     const NGInlineCursor& cursor,
@@ -819,7 +791,7 @@
   const LogicalRect line_height_expanded_rect =
       ExpandSelectionRectToLineHeight(line_break_extended_rect, cursor);
   const PhysicalRect physical_rect =
-      ComputePhysicalRectFor(line_height_expanded_rect, cursor);
+      cursor.Current().ConvertToPhysical(line_height_expanded_rect);
   return physical_rect;
 }
 
@@ -833,7 +805,7 @@
   const LogicalRect line_height_expanded_rect =
       ExpandSelectionRectToLineHeight(logical_rect, cursor);
   const PhysicalRect physical_rect =
-      ComputePhysicalRectFor(line_height_expanded_rect, cursor);
+      cursor.Current().ConvertToPhysical(line_height_expanded_rect);
   return physical_rect;
 }
 
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
index 65e7fd5..fa63c76 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -1827,11 +1827,10 @@
   // frame's transform tree.
   // This asserts that we have the following tree structure:
   // Transform transform=translation=1.000000,2.000000,3.000000
-  //   PaintOffsetTranslation transform=Identity
-  //     PreTranslation transform=translation=7.000000,7.000000,0.000000
-  //       PaintOffsetTranslation transform=Identity
-  //         ScrollTranslation transform=translation=0.000000,0.000000,0.000000
-  //           Transform transform=translation=4.000000,5.000000,6.000000
+  //   PreTranslation transform=translation=7.000000,7.000000,0.000000
+  //     PaintOffsetTranslation transform=Identity
+  //       ScrollTranslation transform=translation=0.000000,0.000000,0.000000
+  //         Transform transform=translation=4.000000,5.000000,6.000000
   auto* inner_document_scroll_translation = inner_div_transform->Parent();
   EXPECT_TRUE(inner_document_scroll_translation->IsIdentity());
   auto* paint_offset_translation = inner_document_scroll_translation->Parent();
@@ -1845,16 +1844,8 @@
     EXPECT_EQ(div_with_transform_properties->Transform(),
               iframe_pre_translation->Parent());
   } else {
-    LayoutObject* iframe_element = GetLayoutObjectByElementId("iframe");
-    const ObjectPaintProperties* iframe_element_properties =
-        iframe_element->FirstFragment().PaintProperties();
-    EXPECT_EQ(iframe_element_properties->PaintOffsetTranslation(),
-              iframe_pre_translation->Parent());
-    EXPECT_EQ(
-        FloatSize(),
-        iframe_element_properties->PaintOffsetTranslation()->Translation2D());
     EXPECT_EQ(div_with_transform_properties->Transform(),
-              iframe_element_properties->PaintOffsetTranslation()->Parent());
+              iframe_pre_translation->Parent());
   }
 }
 
diff --git a/third_party/blink/renderer/core/script/script_loader.cc b/third_party/blink/renderer/core/script/script_loader.cc
index ddaefa49..4871aa3 100644
--- a/third_party/blink/renderer/core/script/script_loader.cc
+++ b/third_party/blink/renderer/core/script/script_loader.cc
@@ -253,7 +253,7 @@
 bool ShouldBlockSyncScriptForFeaturePolicy(const ScriptElementBase* element,
                                            mojom::ScriptType script_type,
                                            bool parser_inserted) {
-  if (element->GetDocument().IsFeatureEnabled(
+  if (element->GetExecutionContext()->IsFeatureEnabled(
           mojom::blink::FeaturePolicyFeature::kSyncScript)) {
     return false;
   }
diff --git a/third_party/blink/renderer/core/style/BUILD.gn b/third_party/blink/renderer/core/style/BUILD.gn
index c22bf4f..9c8276c7 100644
--- a/third_party/blink/renderer/core/style/BUILD.gn
+++ b/third_party/blink/renderer/core/style/BUILD.gn
@@ -40,7 +40,6 @@
     "filter_operation.h",
     "filter_operations.cc",
     "filter_operations.h",
-    "gap_length.h",
     "grid_area.h",
     "grid_length.h",
     "grid_position.h",
diff --git a/third_party/blink/renderer/core/style/gap_length.h b/third_party/blink/renderer/core/style/gap_length.h
deleted file mode 100644
index d0a356f..0000000
--- a/third_party/blink/renderer/core/style/gap_length.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_GAP_LENGTH_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_GAP_LENGTH_H_
-
-#include "third_party/blink/renderer/platform/geometry/length.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-
-class GapLength {
-  DISALLOW_NEW();
-
- public:
-  GapLength() : is_normal_(true) {}
-  GapLength(const Length& length) : is_normal_(false), length_(length) {
-    DCHECK(length.IsSpecified());
-  }
-
-  bool IsNormal() const { return is_normal_; }
-  const Length& GetLength() const {
-    DCHECK(!IsNormal());
-    return length_;
-  }
-
-  bool operator==(const GapLength& o) const {
-    return is_normal_ == o.is_normal_ && length_ == o.length_;
-  }
-
-  bool operator!=(const GapLength& o) const {
-    return is_normal_ != o.is_normal_ || length_ != o.length_;
-  }
-
- private:
-  bool is_normal_;
-  Length length_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_GAP_LENGTH_H_
diff --git a/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc b/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc
index 9c31612..7b42c125 100644
--- a/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc
+++ b/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc
@@ -21,7 +21,6 @@
 #include "third_party/blink/renderer/core/testing/sim/sim_request.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_test.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
-#include "third_party/blink/renderer/platform/graphics/dark_mode_generic_classifier.h"
 #include "third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h"
@@ -71,29 +70,9 @@
                 Image::kSyncDecode);
   }
 
-  // Loads the image from |file_name|, computes features into |features|,
-  // and returns the classification result.
-  bool GetFeaturesAndClassification(
-      const String& file_name,
-      DarkModeImageClassifier::Features* features) {
-    CHECK(features);
-    SCOPED_TRACE(file_name);
-    LoadUsingFileName(file_name);
-    DarkModeImageClassifier dark_mode_image_classifier;
-    dark_mode_image_classifier.SetImageType(
-        DarkModeImageClassifier::ImageType::kSvg);
-    auto features_or_null = dark_mode_image_classifier.GetFeatures(
-        image_.get(), FloatRect(0, 0, image_->width(), image_->height()));
-    CHECK(features_or_null.has_value());
-    (*features) = features_or_null.value();
-    DarkModeClassification result =
-        dark_mode_generic_classifier_.ClassifyWithFeatures(*features);
-    return result == DarkModeClassification::kApplyFilter;
-  }
-
-  DarkModeGenericClassifier* classifier() {
-    return &dark_mode_generic_classifier_;
-  }
+  // TODO(prashant.n): This will be removed in follow-up cl.
+  Image* GetLoadedImage() { return image_.get(); }
+  DarkModeImageClassifier* classifier() { return &dark_mode_image_classifier_; }
 
  private:
   class PauseControlImageObserver
@@ -122,7 +101,7 @@
   };
   Persistent<PauseControlImageObserver> observer_;
   scoped_refptr<SVGImage> image_;
-  DarkModeGenericClassifier dark_mode_generic_classifier_;
+  DarkModeImageClassifier dark_mode_image_classifier_;
 };
 
 const char kAnimatedDocument[] =
@@ -276,9 +255,16 @@
   // Color Buckets Ratio: Low
   // Decision Tree: Apply
   // Neural Network: NA
-  EXPECT_TRUE(GetFeaturesAndClassification("/svg/animations/path-animation.svg",
-                                           &features));
-  EXPECT_EQ(classifier()->ClassifyUsingDecisionTreeForTesting(features),
+  LoadUsingFileName("/svg/animations/path-animation.svg");
+  classifier()->SetImageType(DarkModeImageClassifier::ImageType::kSvg);
+  features = classifier()
+                 ->GetFeatures(GetLoadedImage(),
+                               FloatRect(0, 0, GetLoadedImage()->width(),
+                                         GetLoadedImage()->height()))
+                 .value();
+  EXPECT_EQ(classifier()->ClassifyWithFeatures(features),
+            DarkModeClassification::kApplyFilter);
+  EXPECT_EQ(classifier()->ClassifyUsingDecisionTree(features),
             DarkModeClassification::kApplyFilter);
   EXPECT_FALSE(features.is_colorful);
   EXPECT_TRUE(features.is_svg);
@@ -291,9 +277,17 @@
   // Color Buckets Ratio: Low
   // Decision Tree: Apply
   // Neural Network: NA.
-  EXPECT_TRUE(GetFeaturesAndClassification(
-      "/svg/stroke/zero-length-path-linecap-rendering.svg", &features));
-  EXPECT_EQ(classifier()->ClassifyUsingDecisionTreeForTesting(features),
+  LoadUsingFileName("/svg/stroke/zero-length-path-linecap-rendering.svg");
+  classifier()->SetImageType(DarkModeImageClassifier::ImageType::kSvg);
+  features = classifier()
+                 ->GetFeatures(GetLoadedImage(),
+                               FloatRect(0, 0, GetLoadedImage()->width(),
+                                         GetLoadedImage()->height()))
+                 .value();
+  EXPECT_EQ(classifier()->ClassifyWithFeatures(features),
+            DarkModeClassification::kApplyFilter);
+
+  EXPECT_EQ(classifier()->ClassifyUsingDecisionTree(features),
             DarkModeClassification::kApplyFilter);
   EXPECT_TRUE(features.is_colorful);
   EXPECT_TRUE(features.is_svg);
@@ -306,9 +300,16 @@
   // Color Buckets Ratio: Low
   // Decision Tree: Apply
   // Neural Network: NA.
-  EXPECT_TRUE(GetFeaturesAndClassification(
-      "/svg/foreignObject/fixed-position.svg", &features));
-  EXPECT_EQ(classifier()->ClassifyUsingDecisionTreeForTesting(features),
+  LoadUsingFileName("/svg/foreignObject/fixed-position.svg");
+  classifier()->SetImageType(DarkModeImageClassifier::ImageType::kSvg);
+  features = classifier()
+                 ->GetFeatures(GetLoadedImage(),
+                               FloatRect(0, 0, GetLoadedImage()->width(),
+                                         GetLoadedImage()->height()))
+                 .value();
+  EXPECT_EQ(classifier()->ClassifyWithFeatures(features),
+            DarkModeClassification::kApplyFilter);
+  EXPECT_EQ(classifier()->ClassifyUsingDecisionTree(features),
             DarkModeClassification::kApplyFilter);
   EXPECT_TRUE(features.is_colorful);
   EXPECT_TRUE(features.is_svg);
@@ -321,9 +322,16 @@
   // Color Buckets Ratio: Low
   // Decision Tree: Apply
   // Neural Network: NA.
-  EXPECT_TRUE(GetFeaturesAndClassification("/svg/clip-path/clip-in-mask.svg",
-                                           &features));
-  EXPECT_EQ(classifier()->ClassifyUsingDecisionTreeForTesting(features),
+  LoadUsingFileName("/svg/clip-path/clip-in-mask.svg");
+  classifier()->SetImageType(DarkModeImageClassifier::ImageType::kSvg);
+  features = classifier()
+                 ->GetFeatures(GetLoadedImage(),
+                               FloatRect(0, 0, GetLoadedImage()->width(),
+                                         GetLoadedImage()->height()))
+                 .value();
+  EXPECT_EQ(classifier()->ClassifyWithFeatures(features),
+            DarkModeClassification::kApplyFilter);
+  EXPECT_EQ(classifier()->ClassifyUsingDecisionTree(features),
             DarkModeClassification::kApplyFilter);
   EXPECT_FALSE(features.is_colorful);
   EXPECT_TRUE(features.is_svg);
diff --git a/third_party/blink/renderer/core/svg/svg_image_element.cc b/third_party/blink/renderer/core/svg/svg_image_element.cc
index 46dc7ec0..6b316ff 100644
--- a/third_party/blink/renderer/core/svg/svg_image_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_image_element.cc
@@ -36,8 +36,9 @@
 SVGImageElement::SVGImageElement(Document& document)
     : SVGGraphicsElement(svg_names::kImageTag, document),
       SVGURIReference(this),
-      is_default_overridden_intrinsic_size_(!document.IsFeatureEnabled(
-          mojom::blink::DocumentPolicyFeature::kUnsizedMedia)),
+      is_default_overridden_intrinsic_size_(
+          !GetExecutionContext()->IsFeatureEnabled(
+              mojom::blink::DocumentPolicyFeature::kUnsizedMedia)),
       x_(MakeGarbageCollected<SVGAnimatedLength>(
           this,
           svg_names::kXAttr,
diff --git a/third_party/blink/renderer/core/timing/performance_resource_timing.h b/third_party/blink/renderer/core/timing/performance_resource_timing.h
index 5a7a6f6..8321566 100644
--- a/third_party/blink/renderer/core/timing/performance_resource_timing.h
+++ b/third_party/blink/renderer/core/timing/performance_resource_timing.h
@@ -42,7 +42,6 @@
 #include "third_party/blink/renderer/core/timing/performance_server_timing.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
-#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
 namespace blink {
@@ -151,8 +150,7 @@
   // PerformanceResourceTiming#workerTiming. Null when no service worker handles
   // a request for the resource.
   HeapMojoReceiver<mojom::blink::WorkerTimingContainer,
-                   PerformanceResourceTiming,
-                   HeapMojoWrapperMode::kWithoutContextObserver>
+                   PerformanceResourceTiming>
       worker_timing_receiver_;
 };
 
diff --git a/third_party/blink/renderer/core/timing/profiler_group.cc b/third_party/blink/renderer/core/timing/profiler_group.cc
index ab09a9d..1f7b00f 100644
--- a/third_party/blink/renderer/core/timing/profiler_group.cc
+++ b/third_party/blink/renderer/core/timing/profiler_group.cc
@@ -125,11 +125,13 @@
 }
 
 void ProfilerGroup::WillBeDestroyed() {
-  for (auto& profiler : profilers_) {
+  while (!profilers_.IsEmpty()) {
+    Profiler* profiler = profilers_.begin()->Get();
     DCHECK(profiler);
     CancelProfiler(profiler);
     profiler->RemovedFromProfilerGroup();
     DCHECK(profiler->stopped());
+    DCHECK(!profilers_.Contains(profiler));
   }
 
   if (cpu_profiler_)
@@ -179,6 +181,8 @@
   if (profile)
     profile->Delete();
 
+  profilers_.erase(profiler);
+
   if (--num_active_profilers_ == 0)
     TeardownV8Profiler();
 }
@@ -186,6 +190,7 @@
 void ProfilerGroup::CancelProfiler(Profiler* profiler) {
   DCHECK(cpu_profiler_);
   DCHECK(!profiler->stopped());
+  profilers_.erase(profiler);
   CancelProfilerImpl(profiler->ProfilerId());
 }
 
@@ -193,6 +198,7 @@
                                         Profiler* profiler) {
   DCHECK(cpu_profiler_);
   DCHECK(!profiler->stopped());
+  profilers_.erase(profiler);
   ExecutionContext::From(script_state)
       ->GetTaskRunner(TaskType::kInternalDefault)
       ->PostTask(FROM_HERE,
diff --git a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
index 6c34c81..838751238 100644
--- a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
+++ b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
@@ -741,7 +741,7 @@
 
   if (!async_) {
     if (GetExecutionContext()->IsDocument() &&
-        !GetDocument()->IsFeatureEnabled(
+        !GetExecutionContext()->IsFeatureEnabled(
             mojom::blink::FeaturePolicyFeature::kSyncXHR,
             ReportOptions::kReportOnFailure,
             "Synchronous requests are disabled by Feature Policy.")) {
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn
index df7b03a4..acd2517 100644
--- a/third_party/blink/renderer/modules/BUILD.gn
+++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -364,6 +364,7 @@
     "payments/abort_test.cc",
     "payments/can_make_payment_test.cc",
     "payments/complete_test.cc",
+    "payments/goods/digital_goods_type_converters_unittest.cc",
     "payments/merchant_validation_event_test.cc",
     "payments/on_payment_response_test.cc",
     "payments/payment_address_test.cc",
diff --git a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
index c57a413c..a8b33c2 100644
--- a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
+++ b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
@@ -285,8 +285,8 @@
 
   // We are now ready to inspect worker thread.
   worker_context_client_->WorkerReadyForInspectionOnInitiatorThread(
-      devtools_agent_remote.PassPipe(),
-      devtools_agent_host_receiver.PassPipe());
+      std::move(devtools_agent_remote),
+      std::move(devtools_agent_host_receiver));
 }
 
 std::unique_ptr<CrossThreadFetchClientSettingsObjectData>
diff --git a/third_party/blink/renderer/modules/hid/hid.cc b/third_party/blink/renderer/modules/hid/hid.cc
index 677ef41..ce90c83 100644
--- a/third_party/blink/renderer/modules/hid/hid.cc
+++ b/third_party/blink/renderer/modules/hid/hid.cc
@@ -141,7 +141,7 @@
     return ScriptPromise();
   }
 
-  if (!frame->GetDocument()->IsFeatureEnabled(
+  if (!GetExecutionContext()->IsFeatureEnabled(
           mojom::blink::FeaturePolicyFeature::kHid,
           ReportOptions::kReportOnFailure)) {
     exception_state.ThrowSecurityError(kFeaturePolicyBlocked);
diff --git a/third_party/blink/renderer/modules/imagecapture/image_capture.cc b/third_party/blink/renderer/modules/imagecapture/image_capture.cc
index c858ba8..dfc7126 100644
--- a/third_party/blink/renderer/modules/imagecapture/image_capture.cc
+++ b/third_party/blink/renderer/modules/imagecapture/image_capture.cc
@@ -459,9 +459,12 @@
       (constraints->hasSaturation() && !capabilities_->hasSaturation()) ||
       (constraints->hasSharpness() && !capabilities_->hasSharpness()) ||
       (constraints->hasFocusDistance() && !capabilities_->hasFocusDistance()) ||
-      (HasPanTiltZoomPermissionGranted() &&
-       ((constraints->hasPan() && !capabilities_->hasPan()) ||
-        (constraints->hasTilt() && !capabilities_->hasTilt()))) ||
+      (constraints->hasPan() &&
+       !(capabilities_->hasPan() && HasPanTiltZoomPermissionGranted())) ||
+      (constraints->hasTilt() &&
+       !(capabilities_->hasTilt() && HasPanTiltZoomPermissionGranted())) ||
+      // TODO(crbug.com/934063): Check HasPanTiltZoomPermissionGranted() as well
+      // if upcoming metrics show that zoom may be moved under this permission.
       (constraints->hasZoom() && !capabilities_->hasZoom()) ||
       (constraints->hasTorch() && !capabilities_->hasTorch())) {
     resolver->Reject(MakeGarbageCollected<DOMException>(
@@ -663,12 +666,6 @@
 
   settings->has_pan = constraints->hasPan() && constraints->pan().IsDouble();
   if (settings->has_pan) {
-    if (!HasPanTiltZoomPermissionGranted()) {
-      resolver->Reject(
-          MakeGarbageCollected<DOMException>(DOMExceptionCode::kNotAllowedError,
-                                             "PTZ permission must be granted"));
-      return;
-    }
     const auto pan = constraints->pan().GetAsDouble();
     if (pan < capabilities_->pan()->min() ||
         pan > capabilities_->pan()->max()) {
@@ -682,12 +679,6 @@
 
   settings->has_tilt = constraints->hasTilt() && constraints->tilt().IsDouble();
   if (settings->has_tilt) {
-    if (!HasPanTiltZoomPermissionGranted()) {
-      resolver->Reject(
-          MakeGarbageCollected<DOMException>(DOMExceptionCode::kNotAllowedError,
-                                             "PTZ permission must be granted"));
-      return;
-    }
     const auto tilt = constraints->tilt().GetAsDouble();
     if (tilt < capabilities_->tilt()->min() ||
         tilt > capabilities_->tilt()->max()) {
@@ -701,8 +692,6 @@
 
   settings->has_zoom = constraints->hasZoom() && constraints->zoom().IsDouble();
   if (settings->has_zoom) {
-    // TODO(crbug.com/934063): Check HasPanTiltZoomPermissionGranted() as well
-    // if upcoming metrics show that zoom may be moved under this permission.
     const auto zoom = constraints->zoom().GetAsDouble();
     if (zoom < capabilities_->zoom()->min() ||
         zoom > capabilities_->zoom()->max()) {
diff --git a/third_party/blink/renderer/modules/mediastream/BUILD.gn b/third_party/blink/renderer/modules/mediastream/BUILD.gn
index aca23b09e..50a7623 100644
--- a/third_party/blink/renderer/modules/mediastream/BUILD.gn
+++ b/third_party/blink/renderer/modules/mediastream/BUILD.gn
@@ -126,4 +126,6 @@
     "//third_party/blink/public/mojom:mojom_platform_blink_headers",
     "//third_party/webrtc_overrides:webrtc_component",
   ]
+
+  configs += [ "//third_party/blink/renderer:inside_blink" ]
 }
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_renderer_factory_impl.cc b/third_party/blink/renderer/modules/mediastream/media_stream_renderer_factory_impl.cc
index cd8604de..e5c9a44 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_renderer_factory_impl.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_renderer_factory_impl.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/public/platform/web_media_stream.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_track.h"
 #include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink.h"
 #include "third_party/blink/renderer/modules/mediastream/track_audio_renderer.h"
 #include "third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h"
@@ -130,7 +131,11 @@
         "%s => (creating TrackAudioRenderer for %s audio track)", __func__,
         audio_track->is_local_track() ? "local" : "remote"));
 
-    return new TrackAudioRenderer(audio_components[0].Get(), web_frame,
+    auto* frame =
+        web_frame
+            ? static_cast<LocalFrame*>(WebLocalFrame::ToCoreFrame(*web_frame))
+            : nullptr;
+    return new TrackAudioRenderer(audio_components[0].Get(), frame,
                                   /*session_id=*/base::UnguessableToken(),
                                   String(device_id),
                                   std::move(on_render_error_callback));
diff --git a/third_party/blink/renderer/modules/mediastream/track_audio_renderer.cc b/third_party/blink/renderer/modules/mediastream/track_audio_renderer.cc
index ea9c333..84e2923 100644
--- a/third_party/blink/renderer/modules/mediastream/track_audio_renderer.cc
+++ b/third_party/blink/renderer/modules/mediastream/track_audio_renderer.cc
@@ -19,7 +19,6 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/web/web_local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/modules/mediastream/media_stream_local_frame_wrapper.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
@@ -57,6 +56,13 @@
                                            sample_rate);
 }
 
+WebLocalFrame* ToWebLocalFrame(LocalFrame* frame) {
+  if (!frame)
+    return nullptr;
+
+  return static_cast<WebLocalFrame*>(WebFrame::FromFrame(frame));
+}
+
 }  // namespace
 
 // media::AudioRendererSink::RenderCallback implementation
@@ -147,16 +153,15 @@
 
 TrackAudioRenderer::TrackAudioRenderer(
     const WebMediaStreamTrack& audio_track,
-    WebLocalFrame* playout_web_frame,
+    LocalFrame* playout_frame,
     const base::UnguessableToken& session_id,
     const String& device_id,
     base::RepeatingCallback<void()> on_render_error_callback)
     : audio_track_(audio_track),
-      internal_playout_frame_(
-          std::make_unique<MediaStreamInternalFrameWrapper>(playout_web_frame)),
+      playout_frame_(playout_frame),
       session_id_(session_id),
       task_runner_(
-          playout_web_frame->GetTaskRunner(blink::TaskType::kInternalMedia)),
+          playout_frame->GetTaskRunner(blink::TaskType::kInternalMedia)),
       num_samples_rendered_(0),
       on_render_error_callback_(std::move(on_render_error_callback)),
       playing_(false),
@@ -185,8 +190,7 @@
   DCHECK(!sink_);
   sink_ = Platform::Current()->NewAudioRendererSink(
       WebAudioDeviceSourceType::kNonRtcAudioTrack,
-      internal_playout_frame_->web_frame(),
-      {session_id_, output_device_id_.Utf8()});
+      ToWebLocalFrame(playout_frame_), {session_id_, output_device_id_.Utf8()});
 
   base::AutoLock auto_lock(thread_lock_);
   prior_elapsed_render_time_ = base::TimeDelta();
@@ -283,7 +287,7 @@
   scoped_refptr<media::AudioRendererSink> new_sink =
       Platform::Current()->NewAudioRendererSink(
           WebAudioDeviceSourceType::kNonRtcAudioTrack,
-          internal_playout_frame_->web_frame(), {session_id_, device_id});
+          ToWebLocalFrame(playout_frame_), {session_id_, device_id});
 
   media::OutputDeviceStatus new_sink_status =
       new_sink->GetOutputDeviceInfo().device_status();
@@ -383,8 +387,7 @@
   sink_started_ = false;
   sink_ = Platform::Current()->NewAudioRendererSink(
       WebAudioDeviceSourceType::kNonRtcAudioTrack,
-      internal_playout_frame_->web_frame(),
-      {session_id_, output_device_id_.Utf8()});
+      ToWebLocalFrame(playout_frame_), {session_id_, output_device_id_.Utf8()});
   MaybeStartSink();
 }
 
diff --git a/third_party/blink/renderer/modules/mediastream/track_audio_renderer.h b/third_party/blink/renderer/modules/mediastream/track_audio_renderer.h
index e61743cd..985c674 100644
--- a/third_party/blink/renderer/modules/mediastream/track_audio_renderer.h
+++ b/third_party/blink/renderer/modules/mediastream/track_audio_renderer.h
@@ -29,8 +29,7 @@
 
 namespace blink {
 
-class WebLocalFrame;
-class MediaStreamInternalFrameWrapper;
+class LocalFrame;
 
 // TrackAudioRenderer is a WebMediaStreamAudioRenderer for plumbing audio
 // data generated from either local or remote (but not
@@ -63,7 +62,7 @@
   //
   // Called on the main thread.
   TrackAudioRenderer(const WebMediaStreamTrack& audio_track,
-                     WebLocalFrame* playout_web_frame,
+                     LocalFrame* playout_web_frame,
                      const base::UnguessableToken& session_id,
                      const String& device_id,
                      base::RepeatingCallback<void()> on_render_error_callback);
@@ -129,8 +128,8 @@
   // disconnect with the audio track.
   WebMediaStreamTrack audio_track_;
 
-  // The WebLocalFrame in which the audio is rendered into |sink_|.
-  std::unique_ptr<MediaStreamInternalFrameWrapper> internal_playout_frame_;
+  // The LocalFrame in which the audio is rendered into |sink_|.
+  WeakPersistent<LocalFrame> playout_frame_;
   const base::UnguessableToken session_id_;
 
   // MessageLoop associated with the single thread that performs all control
diff --git a/third_party/blink/renderer/modules/payments/goods/BUILD.gn b/third_party/blink/renderer/modules/payments/goods/BUILD.gn
index f828057..e7c9f39 100644
--- a/third_party/blink/renderer/modules/payments/goods/BUILD.gn
+++ b/third_party/blink/renderer/modules/payments/goods/BUILD.gn
@@ -8,6 +8,8 @@
   sources = [
     "digital_goods_service.cc",
     "digital_goods_service.h",
+    "digital_goods_type_converters.cc",
+    "digital_goods_type_converters.h",
     "dom_window_digital_goods.cc",
     "dom_window_digital_goods.h",
   ]
diff --git a/third_party/blink/renderer/modules/payments/goods/OWNERS b/third_party/blink/renderer/modules/payments/goods/OWNERS
index 5ef460a..b4b867f7 100644
--- a/third_party/blink/renderer/modules/payments/goods/OWNERS
+++ b/third_party/blink/renderer/modules/payments/goods/OWNERS
@@ -1,4 +1,7 @@
 glenrob@chromium.org
 mgiuca@chromium.org
 
+per-file *_type_converter*.*=set noparent
+per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
+
 # COMPONENT: UI>Browser>WebAppInstalls>ChromeOS
diff --git a/third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters.cc b/third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters.cc
new file mode 100644
index 0000000..e9325de
--- /dev/null
+++ b/third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters.cc
@@ -0,0 +1,57 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters.h"
+
+#include "third_party/blink/public/mojom/digital_goods/digital_goods.mojom-blink.h"
+#include "third_party/blink/renderer/modules/payments/payment_event_data_conversion.h"
+
+namespace mojo {
+
+blink::ItemDetails*
+TypeConverter<blink::ItemDetails*, payments::mojom::blink::ItemDetailsPtr>::
+    Convert(const payments::mojom::blink::ItemDetailsPtr& input) {
+  if (!input)
+    return nullptr;
+  blink::ItemDetails* output = blink::ItemDetails::Create();
+  output->setItemId(input->item_id);
+  output->setTitle(input->title);
+  output->setDescription(input->description);
+  output->setPrice(
+      blink::PaymentEventDataConversion::ToPaymentCurrencyAmount(input->price));
+  return output;
+}
+
+WTF::String
+TypeConverter<WTF::String, payments::mojom::blink::BillingResponseCode>::
+    Convert(const payments::mojom::blink::BillingResponseCode& input) {
+  switch (input) {
+    case payments::mojom::blink::BillingResponseCode::kOk:
+      return "ok";
+    case payments::mojom::blink::BillingResponseCode::kError:
+      return "error";
+    case payments::mojom::blink::BillingResponseCode::kBillingUnavailable:
+      return "billingUnavailable";
+    case payments::mojom::blink::BillingResponseCode::kDeveloperError:
+      return "developerError";
+    case payments::mojom::blink::BillingResponseCode::kFeatureNotSupported:
+      return "featureNotSupported";
+    case payments::mojom::blink::BillingResponseCode::kItemAlreadyOwned:
+      return "itemAlreadyOwned";
+    case payments::mojom::blink::BillingResponseCode::kItemNotOwned:
+      return "itemNotOwned";
+    case payments::mojom::blink::BillingResponseCode::kItemUnavailable:
+      return "itemUnavailable";
+    case payments::mojom::blink::BillingResponseCode::kServiceDisconnected:
+      return "serviceDisconnected";
+    case payments::mojom::blink::BillingResponseCode::kServiceUnavailable:
+      return "serviceUnavailable";
+    case payments::mojom::blink::BillingResponseCode::kUserCancelled:
+      return "userCancelled";
+  }
+
+  NOTREACHED();
+}
+
+}  // namespace mojo
diff --git a/third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters.h b/third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters.h
new file mode 100644
index 0000000..cf0cdc1
--- /dev/null
+++ b/third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters.h
@@ -0,0 +1,35 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_GOODS_DIGITAL_GOODS_TYPE_CONVERTERS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_GOODS_DIGITAL_GOODS_TYPE_CONVERTERS_H_
+
+#include <string>
+
+#include "mojo/public/cpp/bindings/type_converter.h"
+#include "third_party/blink/public/mojom/digital_goods/digital_goods.mojom-blink-forward.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_item_details.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace mojo {
+
+// Converts a mojo ItemDetails into a WebIDL ItemDetails.
+// Returns a null IDL struct when a null mojo struct is given as input.
+template <>
+struct MODULES_EXPORT
+    TypeConverter<blink::ItemDetails*, payments::mojom::blink::ItemDetailsPtr> {
+  static blink::ItemDetails* Convert(
+      const payments::mojom::blink::ItemDetailsPtr& input);
+};
+
+template <>
+struct MODULES_EXPORT
+    TypeConverter<WTF::String, payments::mojom::blink::BillingResponseCode> {
+  static WTF::String Convert(
+      const payments::mojom::blink::BillingResponseCode& input);
+};
+
+}  // namespace mojo
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_GOODS_DIGITAL_GOODS_TYPE_CONVERTERS_H_
diff --git a/third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters_unittest.cc b/third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters_unittest.cc
new file mode 100644
index 0000000..fca041df
--- /dev/null
+++ b/third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters_unittest.cc
@@ -0,0 +1,58 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/digital_goods/digital_goods.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_item_details.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_payment_currency_amount.h"
+#include "third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters.h"
+
+namespace blink {
+
+using payments::mojom::blink::BillingResponseCode;
+
+TEST(DigitalGoodsTypeConvertersTest, MojoBillingResponseOkToIdl) {
+  auto response_code = BillingResponseCode::kOk;
+  EXPECT_EQ(mojo::ConvertTo<String>(response_code), "ok");
+}
+
+TEST(DigitalGoodsTypeConvertersTest, MojoBillingResponseErrorToIdl) {
+  auto response_code = BillingResponseCode::kError;
+  EXPECT_EQ(mojo::ConvertTo<String>(response_code), "error");
+}
+
+TEST(DigitalGoodsTypeConvertersTest, MojoItemDetailsToIdl) {
+  auto mojo_item_details = payments::mojom::blink::ItemDetails::New();
+  const String item_id = "shiny-sword-id";
+  const String title = "Shiny Sword";
+  const String description = "A sword that is shiny";
+  const String currency = "AUD";
+  const String value = "100.00";
+
+  mojo_item_details->item_id = item_id;
+  mojo_item_details->title = title;
+  mojo_item_details->description = description;
+  auto price = payments::mojom::blink::PaymentCurrencyAmount::New();
+  price->currency = currency;
+  price->value = value;
+  mojo_item_details->price = std::move(price);
+
+  auto* idl_item_details = mojo_item_details.To<ItemDetails*>();
+  EXPECT_EQ(idl_item_details->itemId(), item_id);
+  EXPECT_EQ(idl_item_details->title(), title);
+  EXPECT_EQ(idl_item_details->description(), description);
+  EXPECT_EQ(idl_item_details->price()->currency(), currency);
+  EXPECT_EQ(idl_item_details->price()->value(), value);
+}
+
+TEST(DigitalGoodsTypeConvertersTest, NullMojoItemDetailsToIdl) {
+  payments::mojom::blink::ItemDetailsPtr mojo_item_details;
+
+  auto* idl_item_details = mojo_item_details.To<ItemDetails*>();
+  EXPECT_EQ(idl_item_details, nullptr);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.cc b/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.cc
index e17a550c..1bdfdfa 100644
--- a/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.cc
+++ b/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.cc
@@ -25,8 +25,7 @@
         ExecutionContext::From(script_state));
   }
 
-  ScriptPromiseResolver* resolver =
-      MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   auto promise = resolver->Promise();
 
   resolver->Resolve(digital_goods_service_);
@@ -35,7 +34,6 @@
 
 void DOMWindowDigitalGoods::Trace(Visitor* visitor) const {
   Supplement<LocalDOMWindow>::Trace(visitor);
-
   visitor->Trace(digital_goods_service_);
 }
 
diff --git a/third_party/blink/renderer/modules/payments/payment_event_data_conversion.cc b/third_party/blink/renderer/modules/payments/payment_event_data_conversion.cc
index 18816cf..a7c77c06 100644
--- a/third_party/blink/renderer/modules/payments/payment_event_data_conversion.cc
+++ b/third_party/blink/renderer/modules/payments/payment_event_data_conversion.cc
@@ -18,22 +18,13 @@
 namespace blink {
 namespace {
 
-PaymentCurrencyAmount* ToPaymentCurrencyAmount(
-    payments::mojom::blink::PaymentCurrencyAmountPtr data) {
-  PaymentCurrencyAmount* amount = PaymentCurrencyAmount::Create();
-  if (!data)
-    return amount;
-  amount->setCurrency(data->currency);
-  amount->setValue(data->value);
-  return amount;
-}
-
 PaymentItem* ToPaymentItem(payments::mojom::blink::PaymentItemPtr data) {
   PaymentItem* item = PaymentItem::Create();
   if (!data)
     return item;
   item->setLabel(data->label);
-  item->setAmount(ToPaymentCurrencyAmount(std::move(data->amount)));
+  item->setAmount(
+      PaymentEventDataConversion::ToPaymentCurrencyAmount(data->amount));
   item->setPending(data->pending);
   return item;
 }
@@ -109,7 +100,7 @@
   PaymentShippingOption* shipping_option = PaymentShippingOption::Create();
 
   shipping_option->setAmount(
-      ToPaymentCurrencyAmount(std::move(option->amount)));
+      PaymentEventDataConversion::ToPaymentCurrencyAmount(option->amount));
   shipping_option->setLabel(option->label);
   shipping_option->setId(option->id);
   shipping_option->setSelected(option->selected);
@@ -118,6 +109,16 @@
 
 }  // namespace
 
+PaymentCurrencyAmount* PaymentEventDataConversion::ToPaymentCurrencyAmount(
+    payments::mojom::blink::PaymentCurrencyAmountPtr& input) {
+  PaymentCurrencyAmount* output = PaymentCurrencyAmount::Create();
+  if (!input)
+    return output;
+  output->setCurrency(input->currency);
+  output->setValue(input->value);
+  return output;
+}
+
 PaymentRequestEventInit* PaymentEventDataConversion::ToPaymentRequestEventInit(
     ScriptState* script_state,
     payments::mojom::blink::PaymentRequestEventDataPtr event_data) {
@@ -139,7 +140,7 @@
     method_data.push_back(ToPaymentMethodData(script_state, std::move(md)));
   }
   event_init->setMethodData(method_data);
-  event_init->setTotal(ToPaymentCurrencyAmount(std::move(event_data->total)));
+  event_init->setTotal(ToPaymentCurrencyAmount(event_data->total));
   HeapVector<Member<PaymentDetailsModifier>> modifiers;
   for (auto& modifier : event_data->modifiers) {
     modifiers.push_back(
diff --git a/third_party/blink/renderer/modules/payments/payment_event_data_conversion.h b/third_party/blink/renderer/modules/payments/payment_event_data_conversion.h
index b6ceee14..d5e436b 100644
--- a/third_party/blink/renderer/modules/payments/payment_event_data_conversion.h
+++ b/third_party/blink/renderer/modules/payments/payment_event_data_conversion.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_EVENT_DATA_CONVERSION_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_EVENT_DATA_CONVERSION_H_
 
+#include "components/payments/mojom/payment_request_data.mojom-blink-forward.h"
 #include "third_party/blink/public/mojom/payments/payment_app.mojom-blink-forward.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_can_make_payment_event_init.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_payment_request_event_init.h"
@@ -20,6 +21,8 @@
   STATIC_ONLY(PaymentEventDataConversion);
 
  public:
+  static PaymentCurrencyAmount* ToPaymentCurrencyAmount(
+      payments::mojom::blink::PaymentCurrencyAmountPtr&);
   static CanMakePaymentEventInit* ToCanMakePaymentEventInit(
       ScriptState*,
       payments::mojom::blink::CanMakePaymentEventDataPtr);
diff --git a/third_party/blink/renderer/modules/peerconnection/BUILD.gn b/third_party/blink/renderer/modules/peerconnection/BUILD.gn
index 27fe410..95f4763f 100644
--- a/third_party/blink/renderer/modules/peerconnection/BUILD.gn
+++ b/third_party/blink/renderer/modules/peerconnection/BUILD.gn
@@ -199,4 +199,6 @@
     "//third_party/blink/renderer/platform",
     "//third_party/webrtc_overrides:webrtc_component",
   ]
+
+  configs += [ "//third_party/blink/renderer:inside_blink" ]
 }
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
index 27cf460..862966d 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
+++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
@@ -74,7 +74,7 @@
   // If document is not allowed to use the policy-controlled feature named
   // "picture-in-picture", return kDisabledByFeaturePolicy status.
   if (RuntimeEnabledFeatures::PictureInPictureAPIEnabled() &&
-      !GetSupplementable()->IsFeatureEnabled(
+      !GetSupplementable()->GetExecutionContext()->IsFeatureEnabled(
           blink::mojom::blink::FeaturePolicyFeature::kPictureInPicture,
           report_failure ? ReportOptions::kReportOnFailure
                          : ReportOptions::kDoNotReport)) {
diff --git a/third_party/blink/renderer/modules/serial/serial.cc b/third_party/blink/renderer/modules/serial/serial.cc
index e7ba241..e8c393e 100644
--- a/third_party/blink/renderer/modules/serial/serial.cc
+++ b/third_party/blink/renderer/modules/serial/serial.cc
@@ -104,7 +104,7 @@
     return ScriptPromise();
   }
 
-  if (!frame->GetDocument()->IsFeatureEnabled(
+  if (!GetExecutionContext()->IsFeatureEnabled(
           mojom::blink::FeaturePolicyFeature::kSerial,
           ReportOptions::kReportOnFailure)) {
     exception_state.ThrowSecurityError(kFeaturePolicyBlocked);
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
index 8cc3133..cc24d5b8 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
@@ -67,19 +67,17 @@
 }
 
 void ServiceWorkerGlobalScopeProxy::BindServiceWorker(
-    mojo::ScopedMessagePipeHandle receiver_pipe) {
+    CrossVariantMojoReceiver<mojom::blink::ServiceWorkerInterfaceBase>
+        receiver) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WorkerGlobalScope()->BindServiceWorker(
-      mojo::PendingReceiver<mojom::blink::ServiceWorker>(
-          std::move(receiver_pipe)));
+  WorkerGlobalScope()->BindServiceWorker(std::move(receiver));
 }
 
 void ServiceWorkerGlobalScopeProxy::BindControllerServiceWorker(
-    mojo::ScopedMessagePipeHandle receiver_pipe) {
+    CrossVariantMojoReceiver<mojom::blink::ControllerServiceWorkerInterfaceBase>
+        receiver) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WorkerGlobalScope()->BindControllerServiceWorker(
-      mojo::PendingReceiver<mojom::blink::ControllerServiceWorker>(
-          std::move(receiver_pipe)));
+  WorkerGlobalScope()->BindControllerServiceWorker(std::move(receiver));
 }
 
 void ServiceWorkerGlobalScopeProxy::OnNavigationPreloadResponse(
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
index 74ab556..940f9274 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
@@ -35,7 +35,9 @@
 
 #include "base/macros.h"
 #include "base/threading/thread_checker.h"
+#include "third_party/blink/public/mojom/service_worker/controller_service_worker.mojom-blink.h"
 #include "third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom-blink.h"
+#include "third_party/blink/public/mojom/service_worker/service_worker.mojom-blink.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h"
 #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h"
@@ -75,9 +77,13 @@
   ~ServiceWorkerGlobalScopeProxy() override;
 
   // WebServiceWorkerContextProxy overrides:
-  void BindServiceWorker(mojo::ScopedMessagePipeHandle receiver_pipe) override;
+  void BindServiceWorker(
+      CrossVariantMojoReceiver<mojom::blink::ServiceWorkerInterfaceBase>
+          receiver) override;
   void BindControllerServiceWorker(
-      mojo::ScopedMessagePipeHandle receiver_pipe) override;
+      CrossVariantMojoReceiver<
+          mojom::blink::ControllerServiceWorkerInterfaceBase> receiver)
+      override;
   void OnNavigationPreloadResponse(
       int fetch_event_id,
       std::unique_ptr<WebURLResponse>,
diff --git a/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc b/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
index 116a424..aa1fbb4 100644
--- a/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
+++ b/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
@@ -145,9 +145,11 @@
   MockServiceWorkerContextClient() = default;
   ~MockServiceWorkerContextClient() override = default;
 
-  MOCK_METHOD2(WorkerReadyForInspectionOnInitiatorThread,
-               void(mojo::ScopedMessagePipeHandle,
-                    mojo::ScopedMessagePipeHandle));
+  MOCK_METHOD2(
+      WorkerReadyForInspectionOnInitiatorThread,
+      void(CrossVariantMojoRemote<mojom::DevToolsAgentInterfaceBase>
+               devtools_agent_remote,
+           CrossVariantMojoReceiver<mojom::DevToolsAgentHostInterfaceBase>));
 
   void WorkerContextStarted(WebServiceWorkerContextProxy* proxy,
                             scoped_refptr<base::SequencedTaskRunner>) override {
@@ -172,8 +174,7 @@
     // Simulates calling blink.mojom.ServiceWorker.InitializeGlobalScope() to
     // unblock the service worker script evaluation.
     mojo::Remote<mojom::blink::ServiceWorker> service_worker;
-    proxy->BindServiceWorker(
-        service_worker.BindNewPipeAndPassReceiver().PassPipe());
+    proxy->BindServiceWorker(service_worker.BindNewPipeAndPassReceiver());
     service_worker->InitializeGlobalScope(
         std::move(host_remote),
         mojom::blink::ServiceWorkerRegistrationObjectInfo::New(
diff --git a/third_party/blink/renderer/modules/webcodecs/DEPS b/third_party/blink/renderer/modules/webcodecs/DEPS
index b037e70..0c94dbc 100644
--- a/third_party/blink/renderer/modules/webcodecs/DEPS
+++ b/third_party/blink/renderer/modules/webcodecs/DEPS
@@ -4,6 +4,7 @@
     "+media/base",
     "+media/filters",
     "+media/media_buildflags.h",
+    "+media/renderers",
     "+media/video",
 
     "+third_party/libyuv",
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.cc b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
index 8b490eb..b848f8f 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_frame.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
@@ -8,10 +8,14 @@
 
 #include "media/base/video_frame.h"
 #include "media/base/video_frame_metadata.h"
+#include "media/renderers/paint_canvas_video_renderer.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_init.h"
 #include "third_party/blink/renderer/core/html/canvas/image_data.h"
 #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
+#include "third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h"
 #include "third_party/blink/renderer/platform/graphics/image.h"
+#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
+#include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
 #include "third_party/libyuv/include/libyuv.h"
 
 namespace blink {
@@ -124,8 +128,63 @@
                                       "ARGB to YUV420 conversion error");
     return nullptr;
   }
+  // TODO(jie.a.chen@intel.com): Figure out the right colorspace and conversion
+  // according to source ImageBitmap.
+  // libyuv::ABGRToI420 seems to assume Bt.601.
+  frame->set_color_space(gfx::ColorSpace::CreateREC601());
   auto* result = MakeGarbageCollected<VideoFrame>(std::move(frame));
   return result;
 }
 
+ScriptPromise VideoFrame::createImageBitmap(ScriptState* script_state,
+                                            const ImageBitmapOptions* options,
+                                            ExceptionState& exception_state) {
+  return ImageBitmapFactories::CreateImageBitmap(
+      script_state, this, base::Optional<IntRect>(), options, exception_state);
+}
+
+IntSize VideoFrame::BitmapSourceSize() const {
+  return IntSize(visibleWidth(), visibleHeight());
+}
+
+ScriptPromise VideoFrame::CreateImageBitmap(ScriptState* script_state,
+                                            base::Optional<IntRect> crop_rect,
+                                            const ImageBitmapOptions* options,
+                                            ExceptionState& exception_state) {
+  if (frame_->IsMappable() && !frame_->HasTextures()) {
+    size_t bytes_per_row = sizeof(SkColor) * visibleWidth();
+    size_t image_pixels_size = bytes_per_row * visibleHeight();
+
+    sk_sp<SkData> image_pixels = TryAllocateSkData(image_pixels_size);
+    if (!image_pixels) {
+      exception_state.ThrowDOMException(DOMExceptionCode::kBufferOverrunError,
+                                        "Out of memory.");
+      return ScriptPromise();
+    }
+    media::PaintCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
+        frame_.get(), image_pixels->writable_data(), bytes_per_row);
+
+    // TODO(jie.a.chen@intel.com): Figure the correct SkColorSpace.
+    sk_sp<SkColorSpace> skColorSpace = SkColorSpace::MakeSRGB();
+    SkImageInfo info =
+        SkImageInfo::Make(visibleWidth(), visibleHeight(), kN32_SkColorType,
+                          kUnpremul_SkAlphaType, std::move(skColorSpace));
+    sk_sp<SkImage> skImage =
+        SkImage::MakeRasterData(info, image_pixels, bytes_per_row);
+    scoped_refptr<StaticBitmapImage> image =
+        UnacceleratedStaticBitmapImage::Create(std::move(skImage));
+    return ImageBitmapSource::FulfillImageBitmap(
+        script_state,
+        MakeGarbageCollected<ImageBitmap>(std::move(image), crop_rect, options),
+        exception_state);
+  }
+
+  // TODO(jie.a.chen@intel.com): AcceleratedStaticImageBitmap for hardware
+  // video frames.
+  exception_state.ThrowDOMException(
+      DOMExceptionCode::kNotSupportedError,
+      "Hardware accelerated video not supported.");
+  return ScriptPromise();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.h b/third_party/blink/renderer/modules/webcodecs/video_frame.h
index 45c5296d..a82e29b 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_frame.h
+++ b/third_party/blink/renderer/modules/webcodecs/video_frame.h
@@ -7,6 +7,7 @@
 
 #include "base/optional.h"
 #include "media/base/video_frame.h"
+#include "third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 
@@ -14,8 +15,11 @@
 class ImageBitmap;
 class ExceptionState;
 class VideoFrameInit;
+class ScriptPromise;
+class ScriptState;
 
-class MODULES_EXPORT VideoFrame final : public ScriptWrappable {
+class MODULES_EXPORT VideoFrame final : public ScriptWrappable,
+                                        public ImageBitmapSource {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
@@ -23,6 +27,16 @@
 
   // video_frame.idl implementation.
   static VideoFrame* Create(VideoFrameInit*, ImageBitmap*, ExceptionState&);
+  ScriptPromise createImageBitmap(ScriptState*,
+                                  const ImageBitmapOptions*,
+                                  ExceptionState&);
+
+  // ImageBitmapSource implementation
+  IntSize BitmapSourceSize() const override;
+  ScriptPromise CreateImageBitmap(ScriptState*,
+                                  base::Optional<IntRect> crop_rect,
+                                  const ImageBitmapOptions*,
+                                  ExceptionState&) override;
 
   uint64_t timestamp() const;
   base::Optional<uint64_t> duration() const;
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.idl b/third_party/blink/renderer/modules/webcodecs/video_frame.idl
index aefb0b0..36438bd 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_frame.idl
+++ b/third_party/blink/renderer/modules/webcodecs/video_frame.idl
@@ -11,6 +11,9 @@
 
   void release();
 
+  [CallWith=ScriptState, RaisesException] Promise<ImageBitmap> createImageBitmap(
+    optional ImageBitmapOptions options = {});
+
   readonly attribute unsigned long long timestamp;  // microseconds
   readonly attribute unsigned long long? duration;  // microseconds
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_queue.cc b/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
index 778e30d..6e82556 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
@@ -154,28 +154,54 @@
 }
 
 void GPUQueue::writeBuffer(GPUBuffer* buffer,
-                           uint64_t bufferOffset,
-                           const DOMArrayBuffer* data,
-                           uint64_t dataOffset,
+                           uint64_t buffer_offset,
+                           const MaybeShared<DOMArrayBufferView>& data,
+                           uint64_t data_byte_offset,
                            ExceptionState& exception_state) {
-  WriteBufferImpl(buffer, bufferOffset, data, dataOffset, {}, exception_state);
+  WriteBufferImpl(buffer, buffer_offset, data->byteLengthAsSizeT(),
+                  data->BaseAddressMaybeShared(), data->TypeSize(),
+                  data_byte_offset, {}, exception_state);
 }
 
 void GPUQueue::writeBuffer(GPUBuffer* buffer,
-                           uint64_t bufferOffset,
-                           const DOMArrayBuffer* data,
-                           uint64_t dataOffset,
-                           uint64_t size,
+                           uint64_t buffer_offset,
+                           const MaybeShared<DOMArrayBufferView>& data,
+                           uint64_t data_byte_offset,
+                           uint64_t byte_size,
                            ExceptionState& exception_state) {
-  WriteBufferImpl(buffer, bufferOffset, data, dataOffset, size,
+  WriteBufferImpl(buffer, buffer_offset, data->byteLengthAsSizeT(),
+                  data->BaseAddressMaybeShared(), data->TypeSize(),
+                  data_byte_offset, byte_size, exception_state);
+}
+
+void GPUQueue::writeBuffer(GPUBuffer* buffer,
+                           uint64_t buffer_offset,
+                           const DOMArrayBufferBase* data,
+                           uint64_t data_byte_offset,
+                           ExceptionState& exception_state) {
+  WriteBufferImpl(buffer, buffer_offset, data->ByteLengthAsSizeT(),
+                  data->DataMaybeShared(), 1, data_byte_offset, {},
+                  exception_state);
+}
+
+void GPUQueue::writeBuffer(GPUBuffer* buffer,
+                           uint64_t buffer_offset,
+                           const DOMArrayBufferBase* data,
+                           uint64_t data_byte_offset,
+                           uint64_t byte_size,
+                           ExceptionState& exception_state) {
+  WriteBufferImpl(buffer, buffer_offset, data->ByteLengthAsSizeT(),
+                  data->DataMaybeShared(), 1, data_byte_offset, byte_size,
                   exception_state);
 }
 
 void GPUQueue::WriteBufferImpl(GPUBuffer* buffer,
                                uint64_t buffer_offset,
-                               const DOMArrayBuffer* data,
-                               uint64_t data_offset,
-                               base::Optional<uint64_t> size,
+                               uint64_t data_byte_length,
+                               const void* data_base_ptr,
+                               unsigned data_bytes_per_element,
+                               uint64_t data_byte_offset,
+                               base::Optional<uint64_t> byte_size,
                                ExceptionState& exception_state) {
   if (buffer_offset % 4 != 0) {
     exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
@@ -183,32 +209,40 @@
     return;
   }
 
-  size_t data_byte_length = data->ByteLengthAsSizeT();
-  if (data_offset > data_byte_length) {
-    exception_state.ThrowRangeError("dataOffset is too large");
+  if (data_byte_offset % data_bytes_per_element != 0) {
+    exception_state.ThrowDOMException(
+        DOMExceptionCode::kOperationError,
+        "dataByteOffset must be a multiple of data.BYTES_PER_ELEMENT");
     return;
   }
 
-  uint64_t max_write_size = data_byte_length - data_offset;
-  uint64_t write_size = max_write_size;
-  if (size.has_value()) {
-    write_size = size.value();
-    if (write_size > max_write_size) {
-      exception_state.ThrowRangeError("size is too large");
+  if (data_byte_offset > data_byte_length) {
+    exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
+                                      "dataByteOffset is too large");
+    return;
+  }
+  uint64_t max_write_size = data_byte_length - data_byte_offset;
+
+  uint64_t write_byte_size = max_write_size;
+  if (byte_size.has_value()) {
+    write_byte_size = byte_size.value();
+    if (write_byte_size > max_write_size) {
+      exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
+                                        "byteSize is too large");
       return;
     }
   }
-  if (write_size % 4 != 0) {
-    exception_state.ThrowRangeError("size must be a multiple of 4");
+  if (write_byte_size % std::max(4u, data_bytes_per_element) != 0) {
+    exception_state.ThrowRangeError(
+        "byteSize must be a multiple of max(4, data.BYTES_PER_ELEMENT)");
     return;
   }
 
-  const uint8_t* data_base =
-      static_cast<const uint8_t*>(data->DataMaybeShared());
-
-  const uint8_t* data_at_offset = &data_base[data_offset];
-  GetProcs().bufferSetSubData(buffer->GetHandle(), buffer_offset, write_size,
-                              data_at_offset);
+  const uint8_t* data_base_ptr_bytes =
+      static_cast<const uint8_t*>(data_base_ptr);
+  const uint8_t* data_ptr = data_base_ptr_bytes + data_byte_offset;
+  GetProcs().bufferSetSubData(buffer->GetHandle(), buffer_offset,
+                              write_byte_size, data_ptr);
 }
 
 // TODO(shaobo.yan@intel.com): Implement this function
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_queue.h b/third_party/blink/renderer/modules/webgpu/gpu_queue.h
index 7799d000..4b29aab 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_queue.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_queue.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_QUEUE_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_QUEUE_H_
 
+#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
 #include "third_party/blink/renderer/modules/webgpu/dawn_object.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 
@@ -12,7 +13,6 @@
 
 class CanvasColorParams;
 class DawnTextureFromImageBitmap;
-class DOMArrayBuffer;
 class ExceptionState;
 class GPUBuffer;
 class GPUCommandBuffer;
@@ -35,21 +35,34 @@
   void signal(GPUFence* fence, uint64_t signal_value);
   GPUFence* createFence(const GPUFenceDescriptor* descriptor);
   void writeBuffer(GPUBuffer* buffer,
-                   uint64_t bufferOffset,
-                   const DOMArrayBuffer* data,
-                   uint64_t dataOffset,
+                   uint64_t buffer_offset,
+                   const MaybeShared<DOMArrayBufferView>& data,
+                   uint64_t data_byte_offset,
                    ExceptionState& exception_state);
   void writeBuffer(GPUBuffer* buffer,
-                   uint64_t bufferOffset,
-                   const DOMArrayBuffer* data,
-                   uint64_t dataOffset,
-                   uint64_t size,
+                   uint64_t buffer_offset,
+                   const MaybeShared<DOMArrayBufferView>& data,
+                   uint64_t data_byte_offset,
+                   uint64_t byte_size,
+                   ExceptionState& exception_state);
+  void writeBuffer(GPUBuffer* buffer,
+                   uint64_t buffer_offset,
+                   const DOMArrayBufferBase* data,
+                   uint64_t data_byte_offset,
+                   ExceptionState& exception_state);
+  void writeBuffer(GPUBuffer* buffer,
+                   uint64_t buffer_offset,
+                   const DOMArrayBufferBase* data,
+                   uint64_t data_byte_offset,
+                   uint64_t byte_size,
                    ExceptionState& exception_state);
   void WriteBufferImpl(GPUBuffer* buffer,
                        uint64_t buffer_offset,
-                       const DOMArrayBuffer* data,
-                       uint64_t data_offset,
-                       base::Optional<uint64_t> size,
+                       uint64_t data_byte_length,
+                       const void* data_base_ptr,
+                       unsigned data_bytes_per_element,
+                       uint64_t data_byte_offset,
+                       base::Optional<uint64_t> byte_size,
                        ExceptionState& exception_state);
   void copyImageBitmapToTexture(
       GPUImageBitmapCopyView* source,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_queue.idl b/third_party/blink/renderer/modules/webgpu/gpu_queue.idl
index 7c5cbfc..5e5a687 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_queue.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_queue.idl
@@ -12,15 +12,21 @@
     GPUFence createFence(optional GPUFenceDescriptor descriptor = {});
     void signal(GPUFence fence, GPUFenceValue signalValue);
 
-    // TODO(crbug.com/1088107): |data| should be [AllowShared] ArrayBuffer,
-    // or maybe [AllowShared] ArrayBufferView
-    // (https://github.com/gpuweb/gpuweb/issues/820)
+    // TODO(crbug.com/1088107): Merge these overloads into one with
+    // [AllowShared] BufferSource (or whatever the upstream spec has), which
+    // would expand this to allow SharedArrayBuffer (can't be implemented now).
+    [RaisesException] void writeBuffer(
+        GPUBuffer buffer,
+        GPUSize64 bufferOffset,
+        [AllowShared] ArrayBufferView data,
+        optional GPUSize64 dataByteOffset = 0,
+        optional GPUSize64 byteSize);
     [RaisesException] void writeBuffer(
         GPUBuffer buffer,
         GPUSize64 bufferOffset,
         ArrayBuffer data,
-        optional GPUSize64 dataOffset = 0,
-        optional GPUSize64 size);
+        optional GPUSize64 dataByteOffset = 0,
+        optional GPUSize64 byteSize);
 
     [RaisesException] void copyImageBitmapToTexture(
         GPUImageBitmapCopyView source,
diff --git a/third_party/blink/renderer/modules/xr/xr_anchor.idl b/third_party/blink/renderer/modules/xr/xr_anchor.idl
index 1db10fc7..724c677 100644
--- a/third_party/blink/renderer/modules/xr/xr_anchor.idl
+++ b/third_party/blink/renderer/modules/xr/xr_anchor.idl
@@ -5,7 +5,7 @@
 [
     SecureContext,
     Exposed=Window,
-    RuntimeEnabled=WebXRIncubations
+    RuntimeEnabled=WebXRAnchors
 ]
 interface XRAnchor {
     [RaisesException]
diff --git a/third_party/blink/renderer/modules/xr/xr_anchor_set.idl b/third_party/blink/renderer/modules/xr/xr_anchor_set.idl
index ddb69dd..aee2cb2 100644
--- a/third_party/blink/renderer/modules/xr/xr_anchor_set.idl
+++ b/third_party/blink/renderer/modules/xr/xr_anchor_set.idl
@@ -5,7 +5,7 @@
 [
     SecureContext,
     Exposed=Window,
-    RuntimeEnabled=WebXRIncubations
+    RuntimeEnabled=WebXRAnchors
 ]
 interface XRAnchorSet {
   readonly setlike<XRAnchor>;
diff --git a/third_party/blink/renderer/modules/xr/xr_frame.idl b/third_party/blink/renderer/modules/xr/xr_frame.idl
index 106f9d5..17bc688c4 100644
--- a/third_party/blink/renderer/modules/xr/xr_frame.idl
+++ b/third_party/blink/renderer/modules/xr/xr_frame.idl
@@ -12,7 +12,7 @@
 
   // More details about the real-world understanding APIs can be found here:
   // https://github.com/immersive-web/real-world-geometry/blob/master/plane-detection-explainer.md
-  [RuntimeEnabled=WebXRIncubations] readonly attribute XRWorldInformation worldInformation;
+  [RuntimeEnabled=WebXRPlaneDetection] readonly attribute XRWorldInformation worldInformation;
 
   [RuntimeEnabled=WebXRAnchors]
   readonly attribute XRAnchorSet trackedAnchors;
diff --git a/third_party/blink/renderer/modules/xr/xr_plane.idl b/third_party/blink/renderer/modules/xr/xr_plane.idl
index a08445c..a647c69 100644
--- a/third_party/blink/renderer/modules/xr/xr_plane.idl
+++ b/third_party/blink/renderer/modules/xr/xr_plane.idl
@@ -12,7 +12,7 @@
 [
     SecureContext,
     Exposed=Window,
-    RuntimeEnabled=WebXRIncubations
+    RuntimeEnabled=WebXRPlaneDetection
 ]
 interface XRPlane {
     readonly attribute XRSpace planeSpace;
diff --git a/third_party/blink/renderer/modules/xr/xr_plane_detection_state.idl b/third_party/blink/renderer/modules/xr/xr_plane_detection_state.idl
index 8b41426a..94573244 100644
--- a/third_party/blink/renderer/modules/xr/xr_plane_detection_state.idl
+++ b/third_party/blink/renderer/modules/xr/xr_plane_detection_state.idl
@@ -7,7 +7,7 @@
 [
     SecureContext,
     Exposed=Window,
-    RuntimeEnabled=WebXRIncubations
+    RuntimeEnabled=WebXRPlaneDetection
 ]
 interface XRPlaneDetectionState {
    readonly attribute boolean enabled;
diff --git a/third_party/blink/renderer/modules/xr/xr_plane_set.idl b/third_party/blink/renderer/modules/xr/xr_plane_set.idl
index f0d3a0d4..8e04e6bd 100644
--- a/third_party/blink/renderer/modules/xr/xr_plane_set.idl
+++ b/third_party/blink/renderer/modules/xr/xr_plane_set.idl
@@ -7,7 +7,7 @@
 [
     SecureContext,
     Exposed=Window,
-    RuntimeEnabled=WebXRIncubations
+    RuntimeEnabled=WebXRPlaneDetection
 ]
 interface XRPlaneSet {
   readonly setlike<XRPlane>;
diff --git a/third_party/blink/renderer/modules/xr/xr_session.idl b/third_party/blink/renderer/modules/xr/xr_session.idl
index 3a8f809..5df7c568 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.idl
+++ b/third_party/blink/renderer/modules/xr/xr_session.idl
@@ -58,8 +58,8 @@
   void cancelAnimationFrame(long handle);
 
   // https://github.com/immersive-web/real-world-geometry/blob/master/plane-detection-explainer.md
-  [RuntimeEnabled=WebXRIncubations] readonly attribute XRWorldTrackingState worldTrackingState;
-  [RuntimeEnabled=WebXRIncubations, RaisesException] void updateWorldTrackingState(optional XRWorldTrackingStateInit state = {});
+  [RuntimeEnabled=WebXRPlaneDetection] readonly attribute XRWorldTrackingState worldTrackingState;
+  [RuntimeEnabled=WebXRPlaneDetection, RaisesException] void updateWorldTrackingState(optional XRWorldTrackingStateInit state = {});
 
   [CallWith=ScriptState, Measure, RaisesException] Promise<void> end();
 
diff --git a/third_party/blink/renderer/modules/xr/xr_system.cc b/third_party/blink/renderer/modules/xr/xr_system.cc
index 43fed0d..dbd54c9 100644
--- a/third_party/blink/renderer/modules/xr/xr_system.cc
+++ b/third_party/blink/renderer/modules/xr/xr_system.cc
@@ -168,9 +168,9 @@
   }
 }
 
-bool HasRequiredFeaturePolicy(const Document* doc,
+bool HasRequiredFeaturePolicy(const ExecutionContext* context,
                               device::mojom::XRSessionFeature feature) {
-  if (!doc)
+  if (!context)
     return false;
 
   switch (feature) {
@@ -184,8 +184,9 @@
     case device::mojom::XRSessionFeature::HIT_TEST:
     case device::mojom::XRSessionFeature::LIGHT_ESTIMATION:
     case device::mojom::XRSessionFeature::ANCHORS:
-      return doc->IsFeatureEnabled(mojom::blink::FeaturePolicyFeature::kWebXr,
-                                   ReportOptions::kReportOnFailure);
+      return context->IsFeatureEnabled(
+          mojom::blink::FeaturePolicyFeature::kWebXr,
+          ReportOptions::kReportOnFailure);
   }
 }
 
@@ -846,10 +847,8 @@
     const String& mode,
     ExceptionState& exception_state,
     bool throw_on_unsupported) {
-  LocalFrame* frame = GetFrame();
-  Document* doc = frame ? frame->GetDocument() : nullptr;
-  if (!doc) {
-    // Reject if the frame or document is inaccessible.
+  if (!GetExecutionContext()) {
+    // Reject if the context is inaccessible.
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                       kNavigatorDetachedError);
     return ScriptPromise();  // Will be rejected by generated bindings
@@ -864,7 +863,7 @@
                                                         throw_on_unsupported);
 
   if (session_mode == device::mojom::blink::XRSessionMode::kImmersiveAr &&
-      !RuntimeEnabledFeatures::WebXRARModuleEnabled(doc)) {
+      !RuntimeEnabledFeatures::WebXRARModuleEnabled(GetExecutionContext())) {
     DVLOG(2) << __func__
              << ": Immersive AR session is only supported if WebXRARModule "
                 "feature is enabled";
@@ -878,8 +877,9 @@
     return promise;
   }
 
-  if (!doc->IsFeatureEnabled(mojom::blink::FeaturePolicyFeature::kWebXr,
-                             ReportOptions::kReportOnFailure)) {
+  if (!GetExecutionContext()->IsFeatureEnabled(
+          mojom::blink::FeaturePolicyFeature::kWebXr,
+          ReportOptions::kReportOnFailure)) {
     // Only allow the call to be made if the appropriate feature policy is in
     // place.
     query->RejectWithSecurityError(kFeaturePolicyBlocked, &exception_state);
@@ -1058,7 +1058,8 @@
                                            "' is not supported for mode: " +
                                            SessionModeToString(session_mode));
         result.invalid_features = true;
-      } else if (!HasRequiredFeaturePolicy(doc, feature_enum.value())) {
+      } else if (!HasRequiredFeaturePolicy(GetExecutionContext(),
+                                           feature_enum.value())) {
         AddConsoleMessage(error_level,
                           "Feature '" + feature_string +
                               "' is not permitted by feature policy");
@@ -1149,7 +1150,7 @@
   }
 
   for (const auto& feature : default_features) {
-    if (HasRequiredFeaturePolicy(doc, feature)) {
+    if (HasRequiredFeaturePolicy(GetExecutionContext(), feature)) {
       required_features.valid_features.insert(feature);
     } else {
       DVLOG(2) << __func__
@@ -1191,10 +1192,9 @@
 // changed. For example, if a new physical device was connected to the system,
 // it might be able to support immersive sessions, where it couldn't before.
 void XRSystem::OnDeviceChanged() {
-  LocalFrame* frame = GetFrame();
-  Document* doc = frame ? frame->GetDocument() : nullptr;
-  if (doc &&
-      doc->IsFeatureEnabled(mojom::blink::FeaturePolicyFeature::kWebXr)) {
+  ExecutionContext* context = GetExecutionContext();
+  if (context &&
+      context->IsFeatureEnabled(mojom::blink::FeaturePolicyFeature::kWebXr)) {
     DispatchEvent(*blink::Event::Create(event_type_names::kDevicechange));
   }
 }
diff --git a/third_party/blink/renderer/modules/xr/xr_world_information.idl b/third_party/blink/renderer/modules/xr/xr_world_information.idl
index b60addc..7aa6950 100644
--- a/third_party/blink/renderer/modules/xr/xr_world_information.idl
+++ b/third_party/blink/renderer/modules/xr/xr_world_information.idl
@@ -7,7 +7,7 @@
 [
     SecureContext,
     Exposed=Window,
-    RuntimeEnabled=WebXRIncubations
+    RuntimeEnabled=WebXRPlaneDetection
 ]
 interface XRWorldInformation {
    readonly attribute XRPlaneSet? detectedPlanes;
diff --git a/third_party/blink/renderer/modules/xr/xr_world_tracking_state.idl b/third_party/blink/renderer/modules/xr/xr_world_tracking_state.idl
index ee714c3..070ee06 100644
--- a/third_party/blink/renderer/modules/xr/xr_world_tracking_state.idl
+++ b/third_party/blink/renderer/modules/xr/xr_world_tracking_state.idl
@@ -7,7 +7,7 @@
 [
     SecureContext,
     Exposed=Window,
-    RuntimeEnabled=WebXRIncubations
+    RuntimeEnabled=WebXRPlaneDetection
 ]
 interface XRWorldTrackingState {
    readonly attribute XRPlaneDetectionState planeDetectionState;
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index bce4020..e341f481 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -865,10 +865,6 @@
     "graphics/dark_mode_color_filter.h",
     "graphics/dark_mode_filter.cc",
     "graphics/dark_mode_filter.h",
-    "graphics/dark_mode_generic_classifier.cc",
-    "graphics/dark_mode_generic_classifier.h",
-    "graphics/dark_mode_icon_classifier.cc",
-    "graphics/dark_mode_icon_classifier.h",
     "graphics/dark_mode_image_classifier.cc",
     "graphics/dark_mode_image_classifier.h",
     "graphics/dark_mode_settings.h",
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
index 97c88d0..66c8420 100644
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -463,20 +463,20 @@
   RuntimeEnabledFeatures::SetWebXRARModuleEnabled(enable);
 }
 
-void WebRuntimeFeatures::EnableWebXRHitTest(bool enable) {
-  RuntimeEnabledFeatures::SetWebXRHitTestEnabled(enable);
+void WebRuntimeFeatures::EnableWebXRCameraAccess(bool enable) {
+  RuntimeEnabledFeatures::SetWebXRCameraAccessEnabled(enable);
 }
 
-void WebRuntimeFeatures::EnableWebXRIncubations(bool enable) {
-  RuntimeEnabledFeatures::SetWebXRIncubationsEnabled(enable);
+void WebRuntimeFeatures::EnableWebXRHitTest(bool enable) {
+  RuntimeEnabledFeatures::SetWebXRHitTestEnabled(enable);
 }
 
 void WebRuntimeFeatures::EnableWebXRLightEstimation(bool enable) {
   RuntimeEnabledFeatures::SetWebXRLightEstimationEnabled(enable);
 }
 
-void WebRuntimeFeatures::EnableWebXRCameraAccess(bool enable) {
-  RuntimeEnabledFeatures::SetWebXRCameraAccessEnabled(enable);
+void WebRuntimeFeatures::EnableWebXRPlaneDetection(bool enable) {
+  RuntimeEnabledFeatures::SetWebXRPlaneDetectionEnabled(enable);
 }
 
 void WebRuntimeFeatures::EnablePresentationAPI(bool enable) {
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc
index 9a0ec6c..44ddf30a 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc
@@ -87,17 +87,9 @@
 
   void CreateCanvasResourceDispatcher() {
     dispatcher_ = std::make_unique<MockCanvasResourceDispatcher>();
-    // TODO(crbug/1035589) Previously a call to the more generic function
-    // `CanvasResourceProvider::Create` was used but due to `presentationMode =
-    // kDefaultPresentationMode` created a sharedBitmap 100% of the time.
-    // Investigate study if the Bitmap fallback makes sense or not.
     resource_provider_ = CanvasResourceProvider::CreateSharedBitmapProvider(
         IntSize(kWidth, kHeight), kLow_SkFilterQuality, CanvasColorParams(),
         dispatcher_->GetWeakPtr());
-    if (!resource_provider_) {
-      resource_provider_ = CanvasResourceProvider::CreateBitmapProvider(
-          IntSize(kWidth, kHeight), kLow_SkFilterQuality, CanvasColorParams());
-    }
   }
 
   MockCanvasResourceDispatcher* Dispatcher() { return dispatcher_.get(); }
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
index 61ef84a..95be9f6 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
@@ -11,8 +11,6 @@
 #include "base/optional.h"
 #include "third_party/blink/renderer/platform/graphics/dark_mode_color_classifier.h"
 #include "third_party/blink/renderer/platform/graphics/dark_mode_color_filter.h"
-#include "third_party/blink/renderer/platform/graphics/dark_mode_generic_classifier.h"
-#include "third_party/blink/renderer/platform/graphics/dark_mode_icon_classifier.h"
 #include "third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_types.h"
@@ -55,21 +53,9 @@
                         Image* image) {
   switch (settings.image_policy) {
     case DarkModeImagePolicy::kFilterSmart: {
-      DarkModeImageClassifier* classifier;
-      switch (settings.classifier_type) {
-        case DarkModeClassifierType::kIcon: {
-          DarkModeIconClassifier icon_classifier;
-          classifier = &icon_classifier;
-          break;
-        }
-        case DarkModeClassifierType::kGeneric: {
-          DarkModeGenericClassifier generic_classifier;
-          classifier = &generic_classifier;
-          break;
-        }
-      }
+      DarkModeImageClassifier classifier;
       DarkModeClassification result =
-          classifier->Classify(image, src_rect, dest_rect);
+          classifier.Classify(image, src_rect, dest_rect);
       return result == DarkModeClassification::kApplyFilter;
     }
     case DarkModeImagePolicy::kFilterNone:
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_generic_classifier.cc b/third_party/blink/renderer/platform/graphics/dark_mode_generic_classifier.cc
deleted file mode 100644
index f14ba372..0000000
--- a/third_party/blink/renderer/platform/graphics/dark_mode_generic_classifier.cc
+++ /dev/null
@@ -1,73 +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/platform/graphics/dark_mode_generic_classifier.h"
-
-#include "third_party/blink/renderer/platform/graphics/darkmode/darkmode_classifier.h"
-#include "third_party/blink/renderer/platform/graphics/image.h"
-
-namespace blink {
-namespace {
-
-// Decision tree lower and upper thresholds for grayscale and color images.
-const float kLowColorCountThreshold[2] = {0.8125, 0.015137};
-const float kHighColorCountThreshold[2] = {1, 0.025635};
-
-DarkModeClassification ClassifyUsingDecisionTree(
-    const DarkModeImageClassifier::Features& features) {
-  float low_color_count_threshold =
-      kLowColorCountThreshold[features.is_colorful];
-  float high_color_count_threshold =
-      kHighColorCountThreshold[features.is_colorful];
-
-  // Very few colors means it's not a photo, apply the filter.
-  if (features.color_buckets_ratio < low_color_count_threshold)
-    return DarkModeClassification::kApplyFilter;
-
-  // Too many colors means it's probably photorealistic, do not apply it.
-  if (features.color_buckets_ratio > high_color_count_threshold)
-    return DarkModeClassification::kDoNotApplyFilter;
-
-  // In-between, decision tree cannot give a precise result.
-  return DarkModeClassification::kNotClassified;
-}
-
-// The neural network expects these features to be in a specific order within
-// the vector. Do not change the order here without also changing the neural
-// network code!
-Vector<float> ToVector(const DarkModeImageClassifier::Features& features) {
-  return {features.is_colorful, features.color_buckets_ratio,
-          features.transparency_ratio, features.background_ratio,
-          features.is_svg};
-}
-
-}  // namespace
-
-DarkModeGenericClassifier::DarkModeGenericClassifier() {}
-
-DarkModeClassification DarkModeGenericClassifier::ClassifyWithFeatures(
-    const Features& features) {
-  DarkModeClassification result = ClassifyUsingDecisionTree(features);
-
-  // If decision tree cannot decide, we use a neural network to decide whether
-  // to filter or not based on all the features.
-  if (result == DarkModeClassification::kNotClassified) {
-    darkmode_tfnative_model::FixedAllocations nn_temp;
-    float nn_out;
-    auto feature_vector = ToVector(features);
-    darkmode_tfnative_model::Inference(&feature_vector[0], &nn_out, &nn_temp);
-    result = nn_out > 0 ? DarkModeClassification::kApplyFilter
-                        : DarkModeClassification::kDoNotApplyFilter;
-  }
-
-  return result;
-}
-
-DarkModeClassification
-DarkModeGenericClassifier::ClassifyUsingDecisionTreeForTesting(
-    const Features& features) {
-  return ClassifyUsingDecisionTree(features);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_generic_classifier.h b/third_party/blink/renderer/platform/graphics/dark_mode_generic_classifier.h
deleted file mode 100644
index d231a26..0000000
--- a/third_party/blink/renderer/platform/graphics/dark_mode_generic_classifier.h
+++ /dev/null
@@ -1,31 +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_PLATFORM_GRAPHICS_DARK_MODE_GENERIC_CLASSIFIER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_DARK_MODE_GENERIC_CLASSIFIER_H_
-
-#include "third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_types.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-
-class PLATFORM_EXPORT DarkModeGenericClassifier
-    : public DarkModeImageClassifier {
-  DISALLOW_NEW();
-
- public:
-  DarkModeGenericClassifier();
-  ~DarkModeGenericClassifier() = default;
-
-  DarkModeClassification ClassifyWithFeatures(
-      const Features& features) override;
-
-  DarkModeClassification ClassifyUsingDecisionTreeForTesting(
-      const Features& features);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_DARK_MODE_GENERIC_CLASSIFIER_H_
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_icon_classifier.cc b/third_party/blink/renderer/platform/graphics/dark_mode_icon_classifier.cc
deleted file mode 100644
index 59476956..0000000
--- a/third_party/blink/renderer/platform/graphics/dark_mode_icon_classifier.cc
+++ /dev/null
@@ -1,16 +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/platform/graphics/dark_mode_icon_classifier.h"
-
-namespace blink {
-
-DarkModeIconClassifier::DarkModeIconClassifier() {}
-
-DarkModeClassification DarkModeIconClassifier::ClassifyWithFeatures(
-    const Features& features) {
-  return DarkModeClassification::kDoNotApplyFilter;
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_icon_classifier.h b/third_party/blink/renderer/platform/graphics/dark_mode_icon_classifier.h
deleted file mode 100644
index 2666e93b..0000000
--- a/third_party/blink/renderer/platform/graphics/dark_mode_icon_classifier.h
+++ /dev/null
@@ -1,27 +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_PLATFORM_GRAPHICS_DARK_MODE_ICON_CLASSIFIER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_DARK_MODE_ICON_CLASSIFIER_H_
-
-#include "third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_types.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-
-class PLATFORM_EXPORT DarkModeIconClassifier : public DarkModeImageClassifier {
-  DISALLOW_NEW();
-
- public:
-  DarkModeIconClassifier();
-  ~DarkModeIconClassifier() = default;
-
-  DarkModeClassification ClassifyWithFeatures(
-      const Features& features) override;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_DARK_MODE_ICON_CLASSIFIER_H_
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
index 906b4e78..918685b 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h"
 
 #include "base/optional.h"
+#include "third_party/blink/renderer/platform/graphics/darkmode/darkmode_classifier.h"
 #include "third_party/blink/renderer/platform/graphics/image.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/hash_traits.h"
@@ -14,6 +15,10 @@
 namespace blink {
 namespace {
 
+// Decision tree lower and upper thresholds for grayscale and color images.
+const float kLowColorCountThreshold[2] = {0.8125, 0.015137};
+const float kHighColorCountThreshold[2] = {1, 0.025635};
+
 bool IsColorGray(const SkColor& color) {
   return abs(static_cast<int>(SkColorGetR(color)) -
              static_cast<int>(SkColorGetG(color))) +
@@ -62,6 +67,12 @@
   return result;
 }
 
+void DarkModeImageClassifier::Reset() {
+  pixels_to_sample_ = kPixelsToSample;
+  blocks_count_horizontal_ = kBlocksCount1D;
+  blocks_count_vertical_ = kBlocksCount1D;
+}
+
 base::Optional<DarkModeImageClassifier::Features>
 DarkModeImageClassifier::GetFeatures(Image* image, const FloatRect& src_rect) {
   SkBitmap bitmap;
@@ -243,10 +254,48 @@
          max_buckets[color_mode == ColorMode::kColor];
 }
 
-void DarkModeImageClassifier::ResetDataMembersToDefaults() {
-  pixels_to_sample_ = kPixelsToSample;
-  blocks_count_horizontal_ = kBlocksCount1D;
-  blocks_count_vertical_ = kBlocksCount1D;
+DarkModeClassification DarkModeImageClassifier::ClassifyWithFeatures(
+    const Features& features) {
+  DarkModeClassification result = ClassifyUsingDecisionTree(features);
+
+  // If decision tree cannot decide, we use a neural network to decide whether
+  // to filter or not based on all the features.
+  if (result == DarkModeClassification::kNotClassified) {
+    darkmode_tfnative_model::FixedAllocations nn_temp;
+    float nn_out;
+
+    // The neural network expects these features to be in a specific order
+    // within float array. Do not change the order here without also changing
+    // the neural network code!
+    float feature_list[]{features.is_colorful, features.color_buckets_ratio,
+                         features.transparency_ratio, features.background_ratio,
+                         features.is_svg};
+
+    darkmode_tfnative_model::Inference(feature_list, &nn_out, &nn_temp);
+    result = nn_out > 0 ? DarkModeClassification::kApplyFilter
+                        : DarkModeClassification::kDoNotApplyFilter;
+  }
+
+  return result;
+}
+
+DarkModeClassification DarkModeImageClassifier::ClassifyUsingDecisionTree(
+    const DarkModeImageClassifier::Features& features) {
+  float low_color_count_threshold =
+      kLowColorCountThreshold[features.is_colorful];
+  float high_color_count_threshold =
+      kHighColorCountThreshold[features.is_colorful];
+
+  // Very few colors means it's not a photo, apply the filter.
+  if (features.color_buckets_ratio < low_color_count_threshold)
+    return DarkModeClassification::kApplyFilter;
+
+  // Too many colors means it's probably photorealistic, do not apply it.
+  if (features.color_buckets_ratio > high_color_count_threshold)
+    return DarkModeClassification::kDoNotApplyFilter;
+
+  // In-between, decision tree cannot give a precise result.
+  return DarkModeClassification::kNotClassified;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h
index a54f2593..5d03164 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_DARK_MODE_IMAGE_CLASSIFIER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_DARK_MODE_IMAGE_CLASSIFIER_H_
 
+#include "base/gtest_prod_util.h"
 #include "base/optional.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_types.h"
@@ -15,17 +16,15 @@
 
 class Image;
 
+FORWARD_DECLARE_TEST(DarkModeImageClassifierTest, FeaturesAndClassification);
+FORWARD_DECLARE_TEST(DarkModeImageClassifierTest, Caching);
+FORWARD_DECLARE_TEST(DarkModeImageClassifierTest, BlocksCount);
+FORWARD_DECLARE_TEST(SVGImageTest, DarkModeClassification);
+
 class PLATFORM_EXPORT DarkModeImageClassifier {
   DISALLOW_NEW();
 
  public:
-  DarkModeImageClassifier();
-  ~DarkModeImageClassifier() = default;
-
-  DarkModeClassification Classify(Image* image,
-                                  const FloatRect& src_rect,
-                                  const FloatRect& dest_rect);
-
   struct Features {
     // True if the image is in color, false if it is grayscale.
     bool is_colorful;
@@ -44,37 +43,22 @@
     float transparency_ratio;
   };
 
-  // Computes the features for a given image.
-  base::Optional<Features> GetFeatures(Image* image, const FloatRect& src_rect);
+  DarkModeImageClassifier();
+  ~DarkModeImageClassifier() = default;
 
-  virtual DarkModeClassification ClassifyWithFeatures(
-      const Features& features) {
-    return DarkModeClassification::kDoNotApplyFilter;
-  }
+  DarkModeClassification Classify(Image* image,
+                                  const FloatRect& src_rect,
+                                  const FloatRect& dest_rect);
 
   enum class ImageType { kBitmap = 0, kSvg = 1 };
-
   void SetImageType(ImageType image_type) { image_type_ = image_type; }
 
-  // Functions for testing.
-
-  void SetHorizontalBlocksCount(int horizontal_blocks) {
-    blocks_count_horizontal_ = horizontal_blocks;
-  }
-
-  void SetVerticalBlocksCount(int vertical_blocks) {
-    blocks_count_vertical_ = vertical_blocks;
-  }
-
-  int HorizontalBlocksCount() { return blocks_count_horizontal_; }
-
-  int VerticalBlocksCount() { return blocks_count_vertical_; }
-
-  void ResetDataMembersToDefaults();
-
-  // End of Functions for testing.
-
  private:
+  DarkModeClassification ClassifyWithFeatures(const Features& features);
+  DarkModeClassification ClassifyUsingDecisionTree(const Features& features);
+  base::Optional<Features> GetFeatures(Image* image, const FloatRect& src_rect);
+  void Reset();
+
   enum class ColorMode { kColor = 0, kGrayscale = 1 };
 
   // Given a SkBitmap, extracts a sample set of pixels (|sampled_pixels|),
@@ -114,6 +98,12 @@
   int blocks_count_vertical_;
 
   ImageType image_type_;
+
+  FRIEND_TEST_ALL_PREFIXES(DarkModeImageClassifierTest,
+                           FeaturesAndClassification);
+  FRIEND_TEST_ALL_PREFIXES(DarkModeImageClassifierTest, Caching);
+  FRIEND_TEST_ALL_PREFIXES(DarkModeImageClassifierTest, BlocksCount);
+  FRIEND_TEST_ALL_PREFIXES(SVGImageTest, DarkModeClassification);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc
index 9a38e0dd..c25a149 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc
@@ -6,7 +6,6 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/graphics/bitmap_image.h"
-#include "third_party/blink/renderer/platform/graphics/dark_mode_generic_classifier.h"
 #include "third_party/blink/renderer/platform/graphics/image.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_image.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
@@ -66,42 +65,19 @@
     return image;
   }
 
-  // Computes features into |features|.
-  void GetFeatures(scoped_refptr<BitmapImage> image,
-                   DarkModeImageClassifier::Features* features) {
-    CHECK(features);
-    dark_mode_image_classifier_.SetImageType(
-        DarkModeImageClassifier::ImageType::kBitmap);
-    auto features_or_null = dark_mode_image_classifier_.GetFeatures(
-        image.get(), FloatRect(0, 0, image->width(), image->height()));
-    CHECK(features_or_null.has_value());
-    (*features) = features_or_null.value();
-  }
-
-  // Returns the classification result.
-  bool GetClassification(const DarkModeImageClassifier::Features features) {
-    DarkModeClassification result =
-        dark_mode_generic_classifier_.ClassifyWithFeatures(features);
-    return result == DarkModeClassification::kApplyFilter;
-  }
-
   DarkModeImageClassifier* image_classifier() {
     return &dark_mode_image_classifier_;
   }
 
-  DarkModeGenericClassifier* generic_classifier() {
-    return &dark_mode_generic_classifier_;
-  }
-
  protected:
   ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
       platform_;
   DarkModeImageClassifier dark_mode_image_classifier_;
-  DarkModeGenericClassifier dark_mode_generic_classifier_;
 };
 
 TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) {
   DarkModeImageClassifier::Features features;
+  scoped_refptr<BitmapImage> image;
 
   // Test Case 1:
   // Grayscale
@@ -111,10 +87,15 @@
 
   // The data members of DarkModeImageClassifier have to be reset for every
   // image as the same classifier object is used for all the tests.
-  image_classifier()->ResetDataMembersToDefaults();
-  GetFeatures(GetImage("/images/resources/grid-large.png"), &features);
-  EXPECT_TRUE(GetClassification(features));
-  EXPECT_EQ(generic_classifier()->ClassifyUsingDecisionTreeForTesting(features),
+  image_classifier()->Reset();
+  image = GetImage("/images/resources/grid-large.png");
+  features = image_classifier()
+                 ->GetFeatures(image.get(),
+                               FloatRect(0, 0, image->width(), image->height()))
+                 .value();
+  EXPECT_EQ(image_classifier()->ClassifyWithFeatures(features),
+            DarkModeClassification::kApplyFilter);
+  EXPECT_EQ(image_classifier()->ClassifyUsingDecisionTree(features),
             DarkModeClassification::kApplyFilter);
   EXPECT_FALSE(features.is_colorful);
   EXPECT_FALSE(features.is_svg);
@@ -127,10 +108,15 @@
   // Color Buckets Ratio: Medium
   // Decision Tree: Can't Decide
   // Neural Network: Apply
-  image_classifier()->ResetDataMembersToDefaults();
-  GetFeatures(GetImage("/images/resources/apng08-ref.png"), &features);
-  EXPECT_FALSE(GetClassification(features));
-  EXPECT_EQ(generic_classifier()->ClassifyUsingDecisionTreeForTesting(features),
+  image_classifier()->Reset();
+  image = GetImage("/images/resources/apng08-ref.png");
+  features = image_classifier()
+                 ->GetFeatures(image.get(),
+                               FloatRect(0, 0, image->width(), image->height()))
+                 .value();
+  EXPECT_EQ(image_classifier()->ClassifyWithFeatures(features),
+            DarkModeClassification::kDoNotApplyFilter);
+  EXPECT_EQ(image_classifier()->ClassifyUsingDecisionTree(features),
             DarkModeClassification::kNotClassified);
   EXPECT_FALSE(features.is_colorful);
   EXPECT_FALSE(features.is_svg);
@@ -143,10 +129,15 @@
   // Color Buckets Ratio: Low
   // Decision Tree: Apply
   // Neural Network: NA.
-  image_classifier()->ResetDataMembersToDefaults();
-  GetFeatures(GetImage("/images/resources/twitter_favicon.ico"), &features);
-  EXPECT_TRUE(GetClassification(features));
-  EXPECT_EQ(generic_classifier()->ClassifyUsingDecisionTreeForTesting(features),
+  image_classifier()->Reset();
+  image = GetImage("/images/resources/twitter_favicon.ico");
+  features = image_classifier()
+                 ->GetFeatures(image.get(),
+                               FloatRect(0, 0, image->width(), image->height()))
+                 .value();
+  EXPECT_EQ(image_classifier()->ClassifyWithFeatures(features),
+            DarkModeClassification::kApplyFilter);
+  EXPECT_EQ(image_classifier()->ClassifyUsingDecisionTree(features),
             DarkModeClassification::kApplyFilter);
   EXPECT_TRUE(features.is_colorful);
   EXPECT_FALSE(features.is_svg);
@@ -159,11 +150,15 @@
   // Color Buckets Ratio: High
   // Decision Tree: Do Not Apply
   // Neural Network: NA.
-  image_classifier()->ResetDataMembersToDefaults();
-  GetFeatures(GetImage("/images/resources/blue-wheel-srgb-color-profile.png"),
-              &features);
-  EXPECT_FALSE(GetClassification(features));
-  EXPECT_EQ(generic_classifier()->ClassifyUsingDecisionTreeForTesting(features),
+  image_classifier()->Reset();
+  image = GetImage("/images/resources/blue-wheel-srgb-color-profile.png");
+  features = image_classifier()
+                 ->GetFeatures(image.get(),
+                               FloatRect(0, 0, image->width(), image->height()))
+                 .value();
+  EXPECT_EQ(image_classifier()->ClassifyWithFeatures(features),
+            DarkModeClassification::kDoNotApplyFilter);
+  EXPECT_EQ(image_classifier()->ClassifyUsingDecisionTree(features),
             DarkModeClassification::kDoNotApplyFilter);
   EXPECT_TRUE(features.is_colorful);
   EXPECT_FALSE(features.is_svg);
@@ -176,10 +171,15 @@
   // Color Buckets Ratio: Medium
   // Decision Tree: Apply
   // Neural Network: NA.
-  image_classifier()->ResetDataMembersToDefaults();
-  GetFeatures(GetImage("/images/resources/ycbcr-444-float.jpg"), &features);
-  EXPECT_TRUE(GetClassification(features));
-  EXPECT_EQ(generic_classifier()->ClassifyUsingDecisionTreeForTesting(features),
+  image_classifier()->Reset();
+  image = GetImage("/images/resources/ycbcr-444-float.jpg");
+  features = image_classifier()
+                 ->GetFeatures(image.get(),
+                               FloatRect(0, 0, image->width(), image->height()))
+                 .value();
+  EXPECT_EQ(image_classifier()->ClassifyWithFeatures(features),
+            DarkModeClassification::kApplyFilter);
+  EXPECT_EQ(image_classifier()->ClassifyUsingDecisionTree(features),
             DarkModeClassification::kApplyFilter);
   EXPECT_TRUE(features.is_colorful);
   EXPECT_FALSE(features.is_svg);
@@ -220,37 +220,41 @@
   scoped_refptr<BitmapImage> image =
       GetImage("/images/resources/grid-large.png");
   DarkModeImageClassifier::Features features;
-  image_classifier()->ResetDataMembersToDefaults();
+  image_classifier()->Reset();
 
   // When the horizontal and vertical blocks counts are lesser than the
   // image dimensions, they should remain unaltered.
-  image_classifier()->SetHorizontalBlocksCount((int)(image->width() - 1));
-  image_classifier()->SetVerticalBlocksCount((int)(image->height() - 1));
-  GetFeatures(image, &features);
-  EXPECT_EQ(image_classifier()->HorizontalBlocksCount(),
-            (int)(image->width() - 1));
-  EXPECT_EQ(image_classifier()->VerticalBlocksCount(),
-            (int)(image->height() - 1));
+  image_classifier()->blocks_count_horizontal_ = image->width() - 1;
+  image_classifier()->blocks_count_vertical_ = image->height() - 1;
+  features = image_classifier()
+                 ->GetFeatures(image.get(),
+                               FloatRect(0, 0, image->width(), image->height()))
+                 .value();
+  EXPECT_EQ(image_classifier()->blocks_count_horizontal_, image->width() - 1);
+  EXPECT_EQ(image_classifier()->blocks_count_vertical_, image->height() - 1);
 
   // When the horizontal and vertical blocks counts are lesser than the
   // image dimensions, they should remain unaltered.
-  image_classifier()->SetHorizontalBlocksCount((int)(image->width()));
-  image_classifier()->SetVerticalBlocksCount((int)(image->height()));
-  GetFeatures(image, &features);
-  EXPECT_EQ(image_classifier()->HorizontalBlocksCount(),
-            (int)(image->width()));
-  EXPECT_EQ(image_classifier()->VerticalBlocksCount(),
-            (int)(image->height()));
+  image_classifier()->blocks_count_horizontal_ = image->width();
+  image_classifier()->blocks_count_vertical_ = image->height();
+  features = image_classifier()
+                 ->GetFeatures(image.get(),
+                               FloatRect(0, 0, image->width(), image->height()))
+                 .value();
+  EXPECT_EQ(image_classifier()->blocks_count_horizontal_, image->width());
+  EXPECT_EQ(image_classifier()->blocks_count_vertical_, image->height());
 
   // When the horizontal and vertical blocks counts are greater than the
   // image dimensions, they should be reduced.
-  image_classifier()->SetHorizontalBlocksCount((int)(image->width() + 1));
-  image_classifier()->SetVerticalBlocksCount((int)(image->height() + 1));
-  GetFeatures(image, &features);
-  EXPECT_EQ(image_classifier()->HorizontalBlocksCount(),
+  image_classifier()->blocks_count_horizontal_ = image->width() + 1;
+  image_classifier()->blocks_count_vertical_ = image->height() + 1;
+  features = image_classifier()
+                 ->GetFeatures(image.get(),
+                               FloatRect(0, 0, image->width(), image->height()))
+                 .value();
+  EXPECT_EQ(image_classifier()->blocks_count_horizontal_,
             floor(image->width()));
-  EXPECT_EQ(image_classifier()->VerticalBlocksCount(),
-            floor(image->height()));
+  EXPECT_EQ(image_classifier()->blocks_count_vertical_, floor(image->height()));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_settings.h b/third_party/blink/renderer/platform/graphics/dark_mode_settings.h
index 50dad6f6..f21bd52b 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_settings.h
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_settings.h
@@ -35,11 +35,6 @@
   kFilterByBackground,
 };
 
-enum class DarkModeClassifierType {
-  kIcon,
-  kGeneric,
-};
-
 // New variables added to this struct should also be added to
 // BuildDarkModeSettings() in
 //   //src/third_party/blink/renderer/core/accessibility/apply_dark_mode.h
@@ -49,7 +44,6 @@
   float image_grayscale_percent = 0.0;  // Valid range from 0.0 to 1.0
   float contrast = 0.0;                 // Valid range from -1.0 to 1.0
   DarkModeImagePolicy image_policy = DarkModeImagePolicy::kFilterNone;
-  DarkModeClassifierType classifier_type = DarkModeClassifierType::kGeneric;
 
   // Text colors with brightness below this threshold will be inverted, and
   // above it will be left as in the original, non-dark-mode page.  Set to 256
diff --git a/third_party/blink/renderer/platform/graphics/image_data_buffer.h b/third_party/blink/renderer/platform/graphics/image_data_buffer.h
index 37f8263c..cc8dc19 100644
--- a/third_party/blink/renderer/platform/graphics/image_data_buffer.h
+++ b/third_party/blink/renderer/platform/graphics/image_data_buffer.h
@@ -60,6 +60,7 @@
   const IntSize& size() const { return size_; }
   int Height() const { return size_.Height(); }
   int Width() const { return size_.Width(); }
+  size_t ComputeByteSize() const { return pixmap_.computeByteSize(); }
 
  private:
   ImageDataBuffer(const IntSize&,
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc b/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc
index 4c60ce0..14efaae1 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc
@@ -13,6 +13,7 @@
 #include "third_party/blink/public/platform/web_media_stream_source.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -82,18 +83,17 @@
   return static_cast<MediaStreamAudioSource*>(source.GetPlatformSource());
 }
 
-bool MediaStreamAudioSource::ConnectToTrack(
-    const WebMediaStreamTrack& blink_track) {
+bool MediaStreamAudioSource::ConnectToTrack(MediaStreamComponent* component) {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  DCHECK(!blink_track.IsNull());
+  DCHECK(component);
   SendLogMessage(base::StringPrintf("ConnectToTrack({track_id=%s})",
-                                    blink_track.Id().Utf8().c_str()));
+                                    component->Id().Utf8().c_str()));
 
   // Sanity-check that there is not already a MediaStreamAudioTrack instance
-  // associated with |blink_track|.
-  if (MediaStreamAudioTrack::From(blink_track)) {
-    LOG(DFATAL)
-        << "Attempting to connect another source to a WebMediaStreamTrack.";
+  // associated with |component|.
+  if (MediaStreamAudioTrack::From(component)) {
+    LOG(DFATAL) << "Attempting to connect another source to a "
+                   "WebMediaStreamTrack/MediaStreamComponent.";
     return false;
   }
 
@@ -106,15 +106,14 @@
   }
 
   // Create and initialize a new MediaStreamAudioTrack and pass ownership of it
-  // to the WebMediaStreamTrack.
-  WebMediaStreamTrack mutable_blink_track = blink_track;
-  mutable_blink_track.SetPlatformTrack(
-      CreateMediaStreamAudioTrack(blink_track.Id().Utf8()));
+  // to the MediaStreamComponent.
+  component->SetPlatformTrack(
+      CreateMediaStreamAudioTrack(component->Id().Utf8()));
 
   // Propagate initial "enabled" state.
-  MediaStreamAudioTrack* const track = MediaStreamAudioTrack::From(blink_track);
+  MediaStreamAudioTrack* const track = MediaStreamAudioTrack::From(component);
   DCHECK(track);
-  track->SetEnabled(blink_track.IsEnabled());
+  track->SetEnabled(component->Enabled());
 
   // If the source is stopped, do not start the track.
   if (is_stopped_)
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h b/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h
index 1dfc873..ae3e88b 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h
@@ -14,7 +14,6 @@
 #include "media/base/limits.h"
 #include "third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_source.h"
 #include "third_party/blink/public/platform/web_media_stream_source.h"
-#include "third_party/blink/public/platform/web_media_stream_track.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_audio_deliverer.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
@@ -28,6 +27,7 @@
 PLATFORM_EXPORT extern const int kFallbackAudioLatencyMs;
 
 class MediaStreamAudioTrack;
+class MediaStreamComponent;
 
 // Represents a source of audio, and manages the delivery of audio data between
 // the source implementation and one or more MediaStreamAudioTracks. This is a
@@ -48,18 +48,18 @@
 //
 //   class MyAudioSource : public MediaStreamAudioSource { ... };
 //
-//   WebMediaStreamSource blink_source = ...;
-//   WebMediaStreamTrack blink_track = ...;
-//   blink_source.setExtraData(new MyAudioSource());  // Takes ownership.
-//   if (MediaStreamAudioSource::From(blink_source)
-//           ->ConnectToTrack(blink_track)) {
+//   MediaStreamSource* media_stream_source = ...;
+//   MediaStreamComponent* media_stream_track = ...;
+//   source->setExtraData(new MyAudioSource());  // Takes ownership.
+//   if (MediaStreamAudioSource::From(media_stream_source)
+//           ->ConnectToTrack(media_stream_track)) {
 //     LOG(INFO) << "Success!";
 //   } else {
 //     LOG(ERROR) << "Failed!";
 //   }
 //   // Regardless of whether ConnectToTrack() succeeds, there will always be a
 //   // MediaStreamAudioTrack instance created.
-//   CHECK(MediaStreamAudioTrack::From(blink_track));
+//   CHECK(MediaStreamAudioTrack::From(media_stream_track));
 class PLATFORM_EXPORT MediaStreamAudioSource
     : public WebPlatformMediaStreamSource {
  public:
@@ -91,7 +91,7 @@
   // implementation of the content::MediaStreamAudioTrack interface, which
   // becomes associated with and owned by |track|. Returns true if the source
   // was successfully started.
-  bool ConnectToTrack(const WebMediaStreamTrack& track);
+  bool ConnectToTrack(MediaStreamComponent* component);
 
   // Returns the current format of the audio passing through this source to the
   // sinks. This can return invalid parameters if the source has not yet been
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index b2397e62..8f8fca4 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -685,7 +685,7 @@
     },
     {
       name: "EncryptedMediaPersistentUsageRecordSession",
-      status: "test",
+      status: "experimental",
     },
     {
       name: "EnterKeyHintAttribute",
@@ -2040,12 +2040,12 @@
       status: "experimental"
     },
     {
-      name: "WebXRIncubations",
+      name: "WebXRLightEstimation",
       depends_on: ["WebXRARModule"],
       status: "experimental",
     },
     {
-      name: "WebXRLightEstimation",
+      name: "WebXRPlaneDetection",
       depends_on: ["WebXRARModule"],
       status: "experimental",
     },
diff --git a/third_party/blink/renderer/platform/wtf/text/string_view.h b/third_party/blink/renderer/platform/wtf/text/string_view.h
index 06611ab..06f7eab 100644
--- a/third_party/blink/renderer/platform/wtf/text/string_view.h
+++ b/third_party/blink/renderer/platform/wtf/text/string_view.h
@@ -70,7 +70,7 @@
 
   // From a literal string or LChar buffer:
   StringView(const LChar* chars, unsigned length)
-      : impl_(StringImpl::empty_), characters8_(chars), length_(length) {}
+      : impl_(StringImpl::empty_), bytes_(chars), length_(length) {}
   StringView(const char* chars, unsigned length)
       : StringView(reinterpret_cast<const LChar*>(chars), length) {}
   StringView(const LChar* chars)
@@ -83,9 +83,7 @@
 
   // From a wide literal string or UChar buffer.
   StringView(const UChar* chars, unsigned length)
-      : impl_(StringImpl::empty16_bit_),
-        characters16_(chars),
-        length_(length) {}
+      : impl_(StringImpl::empty16_bit_), bytes_(chars), length_(length) {}
   StringView(const UChar* chars);
   StringView(const char16_t* chars)
       : StringView(reinterpret_cast<const UChar*>(chars)) {}
@@ -115,22 +113,22 @@
 
   const LChar* Characters8() const {
     DCHECK(Is8Bit());
-    return characters8_;
+    return static_cast<const LChar*>(bytes_);
   }
 
   const UChar* Characters16() const {
     DCHECK(!Is8Bit());
-    return characters16_;
+    return static_cast<const UChar*>(bytes_);
   }
 
   base::span<const LChar> Span8() const {
     DCHECK(Is8Bit());
-    return {characters8_, length_};
+    return {static_cast<const LChar*>(bytes_), length_};
   }
 
   base::span<const UChar> Span16() const {
     DCHECK(!Is8Bit());
-    return {characters16_, length_};
+    return {static_cast<const UChar*>(bytes_), length_};
   }
 
   UChar32 CodepointAt(unsigned i) const {
@@ -174,11 +172,7 @@
 #else
   StringImpl* impl_;
 #endif
-  union {
-    const LChar* characters8_;
-    const UChar* characters16_;
-    const void* bytes_;
-  };
+  const void* bytes_;
   unsigned length_;
 };
 
@@ -188,9 +182,9 @@
     : impl_(view.impl_), length_(length) {
   SECURITY_DCHECK(offset + length <= view.length());
   if (Is8Bit())
-    characters8_ = view.Characters8() + offset;
+    bytes_ = view.Characters8() + offset;
   else
-    characters16_ = view.Characters16() + offset;
+    bytes_ = view.Characters16() + offset;
 }
 
 inline StringView::StringView(const StringImpl* impl) {
@@ -236,9 +230,9 @@
   length_ = length;
   impl_ = const_cast<StringImpl*>(&impl);
   if (impl.Is8Bit())
-    characters8_ = impl.Characters8() + offset;
+    bytes_ = impl.Characters8() + offset;
   else
-    characters16_ = impl.Characters16() + offset;
+    bytes_ = impl.Characters16() + offset;
 }
 
 // Unicode aware case insensitive string matching. Non-ASCII characters might
diff --git a/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py b/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py
index b8213e11..aeee9f4 100644
--- a/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py
+++ b/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py
@@ -36,7 +36,7 @@
 from blinkpy.common.system.log_utils import configure_logging
 from blinkpy.web_tests.models.test_expectations import (TestExpectations,
                                                         ParseError)
-
+from blinkpy.web_tests.models.typ_types import ResultType
 from blinkpy.web_tests.port.factory import platform_options
 
 _log = logging.getLogger(__name__)
@@ -166,7 +166,7 @@
     return failures
 
 
-def _check_existence(host, port, path, expectations):
+def _check_test_existence(host, port, path, expectations):
     failures = []
     for exp in expectations:
         if not exp.test:
@@ -249,12 +249,58 @@
     return failures
 
 
+def _check_never_fix_tests(host, port, path, expectations):
+    if not path.endswith('NeverFixTests'):
+        return []
+
+    def pass_validly_overrides_skip(pass_exp, skip_exp):
+        if skip_exp.results != set([ResultType.Skip]):
+            return False
+        if not skip_exp.tags.issubset(pass_exp.tags):
+            return False
+        if skip_exp.is_glob and pass_exp.test.startswith(skip_exp.test[:-1]):
+            return True
+        base_test = port.lookup_virtual_test_base(pass_exp.test)
+        if not base_test:
+            return False
+        if base_test == skip_exp.test:
+            return True
+        if skip_exp.is_glob and base_test.startswith(skip_exp.test[:-1]):
+            return True
+        return False
+
+    failures = []
+    for i in range(len(expectations)):
+        exp = expectations[i]
+        if (exp.results != set([ResultType.Pass])
+                and exp.results != set([ResultType.Skip])):
+            error = "{}:{} Only one of [ Skip ] and [ Pass ] is allowed".format(
+                host.filesystem.basename(path), exp.lineno)
+            _log.error(error)
+            failures.append(error)
+            continue
+        if exp.is_default_pass or exp.results != set([ResultType.Pass]):
+            continue
+        if any(
+                pass_validly_overrides_skip(exp, expectations[j])
+                for j in range(i - 1, 0, -1)):
+            continue
+        error = (
+            "{}:{} {}: The [ Pass ] entry must override a previous [ Skip ]"
+            " entry with a more specific test name or tags".format(
+                host.filesystem.basename(path), exp.lineno, exp.test))
+        _log.error(error)
+        failures.append(error)
+    return failures
+
+
 def _check_expectations(host, port, path, test_expectations, options):
     # Check for original expectation lines (from get_updated_lines) instead of
     # expectations filtered for the current port (test_expectations).
     expectations = test_expectations.get_updated_lines(path)
-    failures = _check_existence(host, port, path, expectations)
+    failures = _check_test_existence(host, port, path, expectations)
     failures.extend(_check_directory_glob(host, port, path, expectations))
+    failures.extend(_check_never_fix_tests(host, port, path, expectations))
     # TODO(crbug.com/1080691): Change this to failures once
     # wpt_expectations_updater is fixed.
     warnings = []
diff --git a/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations_unittest.py b/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations_unittest.py
index 67e6bda..88562f1 100644
--- a/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations_unittest.py
@@ -346,6 +346,44 @@
         self.assertEquals(len(warnings), 1)
         self.assertRegexpMatches(warnings[0], ':5 .*redundant with.* line 4$')
 
+    def test_never_fix_tests(self):
+        options = optparse.Values({
+            'additional_expectations': [],
+            'platform': 'test',
+            'debug_rwt_logging': False
+        })
+        host = MockHost()
+
+        port = host.port_factory.get(options.platform, options=options)
+        port.virtual_test_suites = lambda: [
+            VirtualTestSuite(
+                prefix='foo', bases=['test', 'test1'], args=['--foo'])
+        ]
+        test_expectations = ('# tags: [ mac win ]\n'
+                             '# results: [ Skip Pass ]\n'
+                             'test/* [ Skip ]\n'
+                             '[ mac ] test1/* [ Skip ]\n'
+                             'test/sub/* [ Pass ]\n'
+                             'test/test1.html [ Pass ]\n'
+                             'test1/foo/* [ Pass ]\n'
+                             'test2/* [ Pass ]\n'
+                             'test2.html [ Skip Pass ]\n'
+                             'virtual/foo/test/* [ Pass ]\n'
+                             'virtual/foo/test1/* [ Pass ]\n')
+        port.expectations_dict = lambda: {'NeverFixTests': test_expectations}
+        port.test_exists = lambda test: True
+        host.port_factory.get = lambda platform, options=None: port
+        host.port_factory.all_port_names = lambda platform=None: [port.name()]
+
+        failures, warnings = lint_test_expectations.lint(host, options)
+        self.assertEqual(warnings, [])
+
+        self.assertEquals(len(failures), 4)
+        self.assertRegexpMatches(failures[0], ':7 .*must override')
+        self.assertRegexpMatches(failures[1], ':8 .*must override')
+        self.assertRegexpMatches(failures[2], ':9 Only one of')
+        self.assertRegexpMatches(failures[3], ':11 .*must override')
+
 
 class CheckVirtualSuiteTest(unittest.TestCase):
     def setUp(self):
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index 7de3984..1ad104b 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -1383,7 +1383,7 @@
 
 # Not expected to pass in default configuration, only virtual test suite.
 crbug.com/830901 fast/webgl/video-metadata/texImage-video-last-uploaded-metadata.html [ Skip ]
-virtual/webgl-extra-video-texture-metadata/fast/webgl/video-metadata/* [ Pass ]
+virtual/webgl-extra-video-texture-metadata/fast/webgl/video-metadata/texImage-video-last-uploaded-metadata.html [ Pass ]
 
 # Below are manual tests from web-platform-tests without automation.
 external/wpt/html/canvas/element/drawing-paths-to-the-canvas/canvas_focus_drawFocusIfNeeded_AAPI_001-manual.html [ Skip ]
@@ -1904,11 +1904,11 @@
 # test that feature when web-platform.test domains are being forced into
 # origin-isolation mode. Note that since we also want coverage of this feature
 # with site isolation enabled, we use a different virtual test suite than
-# not-site-per-process, named no-auto-web-platform-test-origin-isolation.
+# not-site-per-process, named no-auto-wpt-origin-isolation.
 external/wpt/origin-isolation/* [ Skip ]
 wpt_internal/origin-isolation/* [ Skip ]
-virtual/no-auto-wpt-origin-isolation/* [ Pass ]
-virtual/not-site-per-process/* [ Pass ]
+virtual/no-auto-wpt-origin-isolation/external/wpt/origin-isolation/* [ Pass ]
+virtual/no-auto-wpt-origin-isolation/wpt_internal/origin-isolation/* [ Pass ]
 # ==== Tests incompatible with the default WPT Origin Isolation end here ==^^
 
 # Tests using testRunner.useUnfortunateSynchronousResizeMode occasionally fail on Win7,
@@ -2016,8 +2016,10 @@
 # Skip the non-virtualized CORS-RFC1918 blocking tests (`.addressSpace` tests are fine):
 crbug.com/763830 http/tests/security/cors-rfc1918/external-to-internal-fetch.php [ Skip ]
 crbug.com/763830 http/tests/security/cors-rfc1918/external-to-internal-xhr.php [ Skip ]
-virtual/cors-rfc1918/http/tests/security/cors-rfc1918/* [ Pass ]
-virtual/omt-worker-fetch-cors-rfc1918/http/tests/security/cors-rfc1918/* [ Pass ]
+virtual/cors-rfc1918/http/tests/security/cors-rfc1918/external-to-internal-fetch.php [ Pass ]
+virtual/cors-rfc1918/http/tests/security/cors-rfc1918/external-to-internal-xhr.php [ Pass ]
+virtual/omt-worker-fetch-cors-rfc1918/http/tests/security/cors-rfc1918/external-to-internal-fetch.php [ Pass ]
+virtual/omt-worker-fetch-cors-rfc1918/http/tests/security/cors-rfc1918/external-to-internal-xhr.php [ Pass ]
 
 # Memory measurement tests are run as virtual tests.
 external/wpt/measure-memory/* [ Skip ]
@@ -2036,8 +2038,20 @@
 crbug.com/961439 external/wpt/cookies/samesite/setcookie-navigation.https.html?legacy-samesite [ Skip ]
 crbug.com/961439 external/wpt/cookies/samesite/window-open-reload.https.html?legacy-samesite [ Skip ]
 crbug.com/961439 external/wpt/cookies/samesite/window-open.https.html?legacy-samesite [ Skip ]
+
 # Unskip the above tests for virtual/legacy-samesite.
-virtual/legacy-samesite/external/wpt/cookies/samesite/* [ Pass ]
+virtual/legacy-samesite/external/wpt/cookies/samesite/fetch.https.html?legacy-samesite [ Pass ]
+virtual/legacy-samesite/external/wpt/cookies/samesite/form-get-blank-reload.https.html?legacy-samesite [ Pass ]
+virtual/legacy-samesite/external/wpt/cookies/samesite/form-get-blank.https.html?legacy-samesite [ Pass ]
+virtual/legacy-samesite/external/wpt/cookies/samesite/form-post-blank-reload.https.html?legacy-samesite [ Pass ]
+virtual/legacy-samesite/external/wpt/cookies/samesite/form-post-blank.https.html?legacy-samesite [ Pass ]
+virtual/legacy-samesite/external/wpt/cookies/samesite/iframe-reload.https.html?legacy-samesite [ Pass ]
+virtual/legacy-samesite/external/wpt/cookies/samesite/iframe.https.html?legacy-samesite [ Pass ]
+virtual/legacy-samesite/external/wpt/cookies/samesite/img.https.html?legacy-samesite [ Pass ]
+virtual/legacy-samesite/external/wpt/cookies/samesite/setcookie-lax.https.html?legacy-samesite [ Pass ]
+virtual/legacy-samesite/external/wpt/cookies/samesite/setcookie-navigation.https.html?legacy-samesite [ Pass ]
+virtual/legacy-samesite/external/wpt/cookies/samesite/window-open-reload.https.html?legacy-samesite [ Pass ]
+virtual/legacy-samesite/external/wpt/cookies/samesite/window-open.https.html?legacy-samesite [ Pass ]
 
 # Non-legacy SameSite cookie tests do not apply when legacy SameSite behavior is in effect.
 crbug.com/961439 virtual/legacy-samesite/external/wpt/cookies/samesite/fetch.https.html [ Skip ]
@@ -2083,3 +2097,9 @@
 # Remove from virtual tests when FreezeUserAgent is turned on by default.
 crbug.com/955620 http/tests/navigation/frozen-useragent.html [ Skip ]
 virtual/passive-fingerprinting/http/tests/navigation/frozen-useragent.html [ Pass ]
+
+# This test run under virtual suites only.
+crbug.com/1018640 external/wpt/web-bundle/wbn-from-network/* [ Skip ]
+virtual/wbn-from-network/external/wpt/web-bundle/wbn-from-network/* [ Pass ]
+crbug.com/1082020 external/wpt/web-bundle/subresource-loading/* [ Skip ]
+virtual/subresource-web-bundles/external/wpt/web-bundle/subresource-loading/* [ Pass ]
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index a3007113..a181416 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -514,6 +514,23 @@
 crbug.com/24182 [ Mac10.10 ] virtual/threaded/external/wpt/css/css-scroll-snap/snap-after-initial-layout/writing-mode-horizontal-tb.html [ Slow ]
 crbug.com/24182 [ Mac10.10 ] virtual/threaded/external/wpt/css/css-animations/CSSAnimation-canceling.tentative.html [ Slow ]
 
-# These MathML tests operator over a huge dictionary and are slow.
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-auto-auto-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-auto-auto-no-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-auto-fixed-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-auto-fixed-no-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-auto-percentage-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-auto-percentage-no-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-fixed-auto-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-fixed-auto-no-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-fixed-fixed-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-fixed-fixed-no-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-fixed-percentage-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-fixed-percentage-no-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-percentage-auto-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-percentage-auto-no-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-percentage-fixed-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-percentage-fixed-no-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-percentage-percentage-intrinsic-ratio.html [ Slow ]
+crbug.com/1091716 svg/as-object/sizing/svg-in-object-placeholder-percentage-percentage-no-intrinsic-ratio.html [ Slow ]
 
 crbug.com/1043669 [ Mac ] inspector-protocol/emulation/set-vision-deficiency.js [ Slow ]
diff --git a/third_party/blink/web_tests/SmokeTests b/third_party/blink/web_tests/SmokeTests
index b746302..30f4f32 100644
--- a/third_party/blink/web_tests/SmokeTests
+++ b/third_party/blink/web_tests/SmokeTests
@@ -857,7 +857,6 @@
 security/set-form-autocomplete-attribute.html
 shadow-dom/crashes/slots-nested-in-document-tree-crash.html
 shadow-dom/css-cascade-outer-scope2.html
-shadow-dom/slotted-pseudo-element-in-v0-tree-crash.html
 storage/domstorage/localstorage/delete-removal.html
 storage/domstorage/localstorage/simple-usage.html
 storage/domstorage/localstorage/string-conversion.html
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index b4f882d..d3cebda0 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1360,7 +1360,6 @@
 crbug.com/891427 virtual/android/url-bar/bottom-and-top-fixed-sticks-to-top.html [ Failure ]
 ## Next 4 here: https://ci.chromium.org/p/chromium/builders/luci.chromium.try/linux_chromium_rel_ng/216317
 crbug.com/891427 virtual/threaded-no-composited-antialiasing/animations/timing/animation-duration-infinite.html [ Failure ]
-crbug.com/891427 fast/overflow/transformed-frame-scrollIntoView.html [ Crash ]
 
 ### Flaky on trybots:
 ### Note: this list includes anything that flaked even once during my (many)
@@ -1813,6 +1812,10 @@
 crbug.com/1052717 external/wpt/css/css-text/line-break/line-break-normal-hyphens-002.html [ Failure ]
 crbug.com/1052717 external/wpt/css/css-text/line-break/line-break-strict-hyphens-002.html [ Failure ]
 
+# Inseparable characters
+crbug.com/1091631 external/wpt/css/css-text/line-break/line-break-normal-015a.xht [ Failure ]
+crbug.com/1091631 external/wpt/css/css-text/line-break/line-break-strict-015a.xht [ Failure ]
+
 # Link event firing
 crbug.com/922618 external/wpt/html/semantics/document-metadata/the-link-element/link-multiple-error-events.html [ Timeout ]
 crbug.com/922618 external/wpt/html/semantics/document-metadata/the-link-element/link-multiple-load-events.html [ Timeout ]
@@ -2687,6 +2690,12 @@
 crbug.com/1086855 external/wpt/css/css-pseudo/file-chooser-button-001.tentative.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Linux ] external/wpt/mathml/presentation-markup/fractions/frac-invalid-3.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/mathml/presentation-markup/fractions/frac-invalid-3.html [ Failure ]
+crbug.com/626703 [ Win ] external/wpt/mathml/presentation-markup/fractions/frac-invalid-3.html [ Failure ]
+crbug.com/626703 [ Linux ] external/wpt/mathml/presentation-markup/fractions/frac-invalid-2.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/mathml/presentation-markup/fractions/frac-invalid-2.html [ Failure ]
+crbug.com/626703 [ Win ] external/wpt/mathml/presentation-markup/fractions/frac-invalid-2.html [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/infrastructure/reftest/reftest_match-print.html [ Failure ]
 crbug.com/626703 [ Mac ] external/wpt/infrastructure/reftest/reftest_match-print.html [ Failure ]
 crbug.com/626703 [ Win ] external/wpt/infrastructure/reftest/reftest_match-print.html [ Failure ]
@@ -2816,18 +2825,6 @@
 crbug.com/626703 [ Retina ] external/wpt/html/cross-origin-opener-policy/popup-coop-by-sw-from-coop.https.html [ Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/RTCRtpSender-replaceTrack.https.html [ Timeout ]
 crbug.com/626703 [ Win ] external/wpt/webrtc/RTCRtpSender-replaceTrack.https.html [ Timeout ]
-crbug.com/626703 [ Linux ] external/wpt/css/css-text/line-break/line-break-normal-015a.xht [ Failure ]
-crbug.com/626703 [ Mac ] external/wpt/css/css-text/line-break/line-break-normal-015a.xht [ Failure ]
-crbug.com/626703 [ Win ] external/wpt/css/css-text/line-break/line-break-normal-015a.xht [ Failure ]
-crbug.com/626703 [ Linux ] external/wpt/css/css-text/line-break/line-break-strict-015a.xht [ Failure ]
-crbug.com/626703 [ Mac ] external/wpt/css/css-text/line-break/line-break-strict-015a.xht [ Failure ]
-crbug.com/626703 [ Win ] external/wpt/css/css-text/line-break/line-break-strict-015a.xht [ Failure ]
-crbug.com/626703 [ Linux ] external/wpt/css/css-text/line-break/line-break-strict-015b.xht [ Failure ]
-crbug.com/626703 [ Mac ] external/wpt/css/css-text/line-break/line-break-strict-015b.xht [ Failure ]
-crbug.com/626703 [ Win ] external/wpt/css/css-text/line-break/line-break-strict-015b.xht [ Failure ]
-crbug.com/626703 [ Linux ] external/wpt/css/css-text/line-break/line-break-normal-015b.xht [ Failure ]
-crbug.com/626703 [ Mac ] external/wpt/css/css-text/line-break/line-break-normal-015b.xht [ Failure ]
-crbug.com/626703 [ Win ] external/wpt/css/css-text/line-break/line-break-normal-015b.xht [ Failure ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/preload/onload-event.html [ Timeout ]
 crbug.com/626703 [ Mac10.10 ] external/wpt/storage/estimate-indexeddb.https.any.worker.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.10 ] external/wpt/fetch/origin/assorted.window.html [ Failure Timeout ]
@@ -3838,19 +3835,9 @@
 
 # Ignore these - they are tests of the disabled features. Eventually remove these.
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/access-document-of-detached-stylesheetlist-crash.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/content-after-style.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/content-reprojection-dynamic.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/distribution-attribute-modified.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/distribution-className-modified.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/distribution-id-modified.html [ Skip ]
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/distribution-update-fonts-load.html [ Skip ]
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/form-in-shadow.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/no-style-sharing-with-uncommon-attribute-and-pseudo-content.html [ Skip ]
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/no-style-sharing-with-uncommon-attribute-nodes.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/reprojection-attribute-modified.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/reprojection-className-modified.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/reprojection-id-modified.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/shadow-contents-fallback-dynamic.html [ Skip ]
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/shadow-dynamic-style-change-via-mutation-and-selector.html [ Skip ]
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/shadow-element-rendering-single.html [ Skip ]
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/shadowhost-keyframes.html [ Skip ]
@@ -3861,19 +3848,11 @@
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/gesture-tapHighlight-shadow-tree.html [ Skip ]
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/import-rule-in-shadow-tree-needs-document-style-recalc.html [ Skip ]
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/scrollbar.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/shadow-contents-select.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/style-sharing-with-content-and-host.html [ Skip ]
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/svg-style-in-shadow-tree.xhtml [ Skip ]
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/text-node-in-shadow.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/content-reprojection-complex.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/content-reprojection-fallback-reprojection.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/content-reprojection-fallback.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/content-reprojection-shadow.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/content-whitespace-attach.html [ Skip ]
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/custom-pseudo-scope.html [ Skip ]
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/dynamically-created-shadow-root.html [ Skip ]
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/new-fallback.html [ Skip ]
-crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/shadow-content-crash.html [ Skip ]
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/shadow-on-image.html [ Skip ]
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/shadowdom-for-button-complex-shadow.html [ Skip ]
 crbug.com/937746 virtual/web-components-v0-disabled/fast/dom/shadow/shadowdom-for-button-without-shadow.html [ Skip ]
@@ -5379,7 +5358,7 @@
 
 # Sheriff 2019-11-29
 crbug.com/1019079 fast/canvas/OffscreenCanvas-placeholder-createImageBitmap.html [ Pass Failure ]
-crbug.com/1027434 external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html [ Pass Timeout ]
+crbug.com/1027434 external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html [ Pass Failure Timeout ]
 
 # Sheriff 2019-12-02
 crbug.com/1029528 [ Linux ] http/tests/devtools/network/oopif-content.js [ Pass Failure ]
@@ -5459,9 +5438,6 @@
 # Sheriff 2019-12-30
 crbug.com/1038354 fast/scroll-snap/snaps-after-scrollbar-scrolling.html [ Pass Failure ]
 
-# These tests will pass once the --enable-features=WebBundlesFromNetwork flag is enabled by default.
-crbug.com/1018640 external/wpt/web-bundle/* [ Skip ]
-
 # Sheriff 2020-01-02
 crbug.com/1038656 [ Mac ] http/tests/devtools/coverage/coverage-view-unused.js [ Pass Failure ]
 crbug.com/1038656 [ Win ] http/tests/devtools/coverage/coverage-view-unused.js [ Pass Failure ]
@@ -5684,7 +5660,7 @@
 
 # Upcoming DevTools change
 crbug.com/1006759 http/tests/devtools/profiler/cpu-profiler-save-load.js [ Pass Failure Timeout ]
-crbug.com/1006759 http/tests/devtools/profiler/heap-snapshot-loader.js [ Pass Failure Timeout ]
+crbug.com/1006759 http/tests/devtools/profiler/heap-snapshot-loader.js [ Pass Failure ]
 
 # Temporarily disabled to land changes in DevTools, multiple dependent CLs
 # [1] https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2049183
@@ -5811,7 +5787,6 @@
 
 crbug.com/1058888 [ Linux ] animations/animationworklet/peek-updated-composited-property-on-main.html [ Pass Failure ]
 
-crbug.com/1086066 external/wpt/html/cross-origin-embedder-policy/no-secure-context.html [ Timeout ]
 crbug.com/1015187 external/wpt/html/cross-origin-embedder-policy/none.https.html [ Pass Timeout ]
 crbug.com/1013523 external/wpt/html/cross-origin-embedder-policy/require-corp.https.html [ Failure Pass ]
 crbug.com/626703 [ Debug ] external/wpt/html/cross-origin-embedder-policy/reporting-navigation.https.html [ Pass Failure ]
@@ -5906,8 +5881,6 @@
 crbug.com/1011811 http/tests/devtools/network/download.js [ Pass Failure ]
 crbug.com/1011811 http/tests/devtools/sxg/sxg-disable-cache.js [ Pass Failure ]
 crbug.com/1080609 virtual/threaded/external/wpt/scroll-animations/element-based-offset.html [ Pass Failure ]
-crbug.com/1082963 http/tests/devtools/console/console-revoke-error.js [ Pass Failure ]
-crbug.com/1082963 http/tests/devtools/console/console-timestamp.js [ Pass Failure ]
 
 # Fails when test moved to use full compositor pipe.
 crbug.com/1085832 [ Fuchsia ] images/size-failure.html [ Timeout ]
@@ -5935,6 +5908,10 @@
 crbug.com/1083362 compositing/reflections/load-video-in-reflection.html [ Pass Failure ]
 crbug.com/1087471 [ Linux ] virtual/threaded/synthetic_gestures/synthetic-pinch-zoom-gesture-touchscreen-zoom-in-slow.html [ Pass Failure ]
 
+# Temporary disabling to allow landing https://webrtc-review.googlesource.com/c/src/+/176509
+crbug.com/webrtc/8787 external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https.html [ Pass Failure ]
+crbug.com/webrtc/8787 external/wpt/webrtc/RTCPeerConnection-getStats.https.html [ Pass Failure ]
+
 # Sheriff 2020-06-01
 # Also see crbug.com/626703, these timed-out before but now fail as well.
 crbug.com/1088220 [ Linux ] external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-failure.https.sub.html [ Pass Failure Timeout ]
@@ -5959,5 +5936,4 @@
 
 # Sheriff 2020-06-04
 crbug.com/1041973 virtual/web-components-v0-disabled/external/wpt/html/semantics/forms/constraints/form-validation-reportValidity.html [ Pass Failure Timeout ]
-crbug.com/1090087 transforms/2d/transform-2d.html [ Pass Timeout ]
 crbug.com/1057060 fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Pass Failure Timeout ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 99d052c..f238112a 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -499,7 +499,8 @@
   },
   {
     "prefix": "no-auto-wpt-origin-isolation",
-    "bases": ["external/wpt/origin-isolation"],
+    "bases": ["external/wpt/origin-isolation",
+              "wpt_internal/origin-isolation"],
     "args": ["--disable-auto-wpt-origin-isolation"]
   },
   {
@@ -797,5 +798,10 @@
     "prefix": "out-of-blink-cspee",
     "bases": [ "external/wpt/content-security-policy/embedded-enforcement" ],
     "args": [ "--enable-features=OutOfBlinkCSPEE" ]
+  },
+  {
+    "prefix": "subresource-web-bundles",
+    "bases": [ "external/wpt/web-bundle/subresource-loading" ],
+    "args": [ "--enable-blink-features=SubresourceWebBundles" ]
   }
 ]
diff --git a/third_party/blink/web_tests/animations/interpolation/svg-lighting-color-interpolation.html b/third_party/blink/web_tests/animations/interpolation/svg-lighting-color-interpolation.html
index fb7d1fc..11da28b 100644
--- a/third_party/blink/web_tests/animations/interpolation/svg-lighting-color-interpolation.html
+++ b/third_party/blink/web_tests/animations/interpolation/svg-lighting-color-interpolation.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <meta charset="UTF-8">
+<meta name="timeout" content="long">
 <style>
 .container {
   display: inline-block;
diff --git a/third_party/blink/web_tests/compositing/force-compositing-mode/overflow-iframe-enter-compositing-expected.txt b/third_party/blink/web_tests/compositing/force-compositing-mode/overflow-iframe-enter-compositing-expected.txt
index 57fb961..f9898ed 100644
--- a/third_party/blink/web_tests/compositing/force-compositing-mode/overflow-iframe-enter-compositing-expected.txt
+++ b/third_party/blink/web_tests/compositing/force-compositing-mode/overflow-iframe-enter-compositing-expected.txt
@@ -7,32 +7,27 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME id='parent-iframe'",
-      "bounds": [154, 154],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [508, 516],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "ContentsLayer for Horizontal Scrollbar Layer",
       "position": [0, 135],
       "bounds": [135, 15],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [135, 0],
       "bounds": [15, 135],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "Scroll Corner Layer",
       "position": [135, 135],
       "bounds": [15, 15],
-      "transform": 2
+      "transform": 1
     }
   ],
   "transforms": [
@@ -42,17 +37,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [8, 8, 0, 1]
-      ]
-    },
-    {
-      "id": 2,
-      "parent": 1,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [2, 2, 0, 1]
+        [10, 10, 0, 1]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/compositing/force-compositing-mode/overflow-iframe-layer-expected.txt b/third_party/blink/web_tests/compositing/force-compositing-mode/overflow-iframe-layer-expected.txt
index 4d386ec..f9898ed 100644
--- a/third_party/blink/web_tests/compositing/force-compositing-mode/overflow-iframe-layer-expected.txt
+++ b/third_party/blink/web_tests/compositing/force-compositing-mode/overflow-iframe-layer-expected.txt
@@ -7,32 +7,27 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME id='iframe'",
-      "bounds": [154, 154],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [508, 516],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "ContentsLayer for Horizontal Scrollbar Layer",
       "position": [0, 135],
       "bounds": [135, 15],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [135, 0],
       "bounds": [15, 135],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "Scroll Corner Layer",
       "position": [135, 135],
       "bounds": [15, 15],
-      "transform": 2
+      "transform": 1
     }
   ],
   "transforms": [
@@ -42,17 +37,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [8, 8, 0, 1]
-      ]
-    },
-    {
-      "id": 2,
-      "parent": 1,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [2, 2, 0, 1]
+        [10, 10, 0, 1]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/compositing/iframes/become-composited-nested-iframes-expected.txt b/third_party/blink/web_tests/compositing/iframes/become-composited-nested-iframes-expected.txt
index a57eae1..4fe6dd12 100644
--- a/third_party/blink/web_tests/compositing/iframes/become-composited-nested-iframes-expected.txt
+++ b/third_party/blink/web_tests/compositing/iframes/become-composited-nested-iframes-expected.txt
@@ -7,62 +7,42 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [284, 204],
+      "name": "LayoutView #document",
+      "bounds": [280, 200],
       "transform": 1
     },
     {
       "name": "LayoutView #document",
-      "bounds": [280, 200],
+      "bounds": [250, 170],
+      "contentsOpaqueForText": true,
+      "backgroundColor": "#C0C0C0",
       "transform": 2
     },
     {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [252, 172],
+      "name": "LayoutNGBlockFlow DIV id='iframe-content' class='box'",
+      "bounds": [210, 210],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
       "transform": 3
     },
     {
       "name": "LayoutView #document",
-      "bounds": [250, 170],
-      "contentsOpaqueForText": true,
-      "backgroundColor": "#C0C0C0",
+      "bounds": [280, 200],
       "transform": 4
     },
     {
-      "name": "LayoutNGBlockFlow DIV id='iframe-content' class='box'",
-      "bounds": [210, 210],
-      "contentsOpaque": true,
-      "backgroundColor": "#0000FF",
-      "transform": 5
-    },
-    {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [284, 204],
-      "transform": 6
-    },
-    {
-      "name": "LayoutView #document",
-      "bounds": [280, 200],
-      "transform": 7
-    },
-    {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [252, 172],
-      "transform": 8
-    },
-    {
       "name": "LayoutView #document",
       "bounds": [250, 170],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 9
+      "transform": 5
     },
     {
       "name": "LayoutNGBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 10
+      "transform": 6
     },
     {
       "name": "LayoutNGBlockFlow DIV id='box' class='composited'",
@@ -84,7 +64,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [20, 120, 0, 1]
+        [22, 122, 0, 1]
       ]
     },
     {
@@ -94,7 +74,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [2, 2, 0, 1]
+        [9, 9, 0, 1]
       ]
     },
     {
@@ -104,17 +84,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [8, 8, 0, 1]
+        [18, 10, 0, 1]
       ]
     },
     {
       "id": 4,
-      "parent": 3,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [1, 1, 0, 1]
+        [22, 346, 0, 1]
       ]
     },
     {
@@ -124,51 +103,12 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [18, 10, 0, 1]
+        [9, 9, 0, 1]
       ]
     },
     {
       "id": 6,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [20, 344, 0, 1]
-      ]
-    },
-    {
-      "id": 7,
-      "parent": 6,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [2, 2, 0, 1]
-      ]
-    },
-    {
-      "id": 8,
-      "parent": 7,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [8, 8, 0, 1]
-      ]
-    },
-    {
-      "id": 9,
-      "parent": 8,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [1, 1, 0, 1]
-      ]
-    },
-    {
-      "id": 10,
-      "parent": 9,
+      "parent": 5,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/blink/web_tests/compositing/iframes/become-overlapped-iframe-expected.txt b/third_party/blink/web_tests/compositing/iframes/become-overlapped-iframe-expected.txt
index 4c0ba73..c4920dc 100644
--- a/third_party/blink/web_tests/compositing/iframes/become-overlapped-iframe-expected.txt
+++ b/third_party/blink/web_tests/compositing/iframes/become-overlapped-iframe-expected.txt
@@ -7,29 +7,24 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame (floating) IFRAME id='iframe'",
-      "bounds": [350, 200],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [305, 230],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutNGBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [305, 0],
       "bounds": [15, 170],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutNGBlockFlow (positioned) DIV id='overlay'",
@@ -45,7 +40,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [58, 58, 0, 1]
+        [73, 73, 0, 1]
       ]
     },
     {
@@ -55,16 +50,6 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
-      ]
-    },
-    {
-      "id": 3,
-      "parent": 2,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [18, 10, 0, 1]
       ]
     }
diff --git a/third_party/blink/web_tests/compositing/iframes/connect-compositing-iframe-delayed-expected.txt b/third_party/blink/web_tests/compositing/iframes/connect-compositing-iframe-delayed-expected.txt
index e7a3749..86915b9 100644
--- a/third_party/blink/web_tests/compositing/iframes/connect-compositing-iframe-delayed-expected.txt
+++ b/third_party/blink/web_tests/compositing/iframes/connect-compositing-iframe-delayed-expected.txt
@@ -9,37 +9,31 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME id='iframe'",
-      "position": [-30, -30],
-      "bounds": [390, 240],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [285, 230],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutNGBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [285, 0],
       "bounds": [15, 150],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutNGBlockFlow DIV id='box' class='composited'",
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 4
+      "transform": 3
     }
   ],
   "transforms": [
@@ -49,7 +43,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [28, 128, 0, 1]
+        [43, 143, 0, 1]
       ]
     },
     {
@@ -59,21 +53,11 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
-      ]
-    },
-    {
-      "id": 3,
-      "parent": 2,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [18, 10, 0, 1]
       ]
     },
     {
-      "id": 4,
+      "id": 3,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/blink/web_tests/compositing/iframes/enter-compositing-iframe-expected.txt b/third_party/blink/web_tests/compositing/iframes/enter-compositing-iframe-expected.txt
index 64c99bd0..0b767de 100644
--- a/third_party/blink/web_tests/compositing/iframes/enter-compositing-iframe-expected.txt
+++ b/third_party/blink/web_tests/compositing/iframes/enter-compositing-iframe-expected.txt
@@ -7,30 +7,24 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME id='parent-iframe'",
-      "position": [-30, -30],
-      "bounds": [390, 240],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [285, 230],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutNGBlockFlow DIV id='test' class='composited box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [285, 0],
       "bounds": [15, 150],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutNGBlockFlow (positioned) DIV class='overlay'",
@@ -46,7 +40,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [28, 28, 0, 1]
+        [43, 43, 0, 1]
       ]
     },
     {
@@ -56,16 +50,6 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
-      ]
-    },
-    {
-      "id": 3,
-      "parent": 2,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [18, 10, 0, 1]
       ]
     }
diff --git a/third_party/blink/web_tests/compositing/iframes/iframe-resize-expected.txt b/third_party/blink/web_tests/compositing/iframes/iframe-resize-expected.txt
index 955eef70..b1c4380 100644
--- a/third_party/blink/web_tests/compositing/iframes/iframe-resize-expected.txt
+++ b/third_party/blink/web_tests/compositing/iframes/iframe-resize-expected.txt
@@ -7,30 +7,24 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME id='parent-iframe' class='bigger'",
-      "position": [-30, -30],
-      "bounds": [490, 210],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [385, 230],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutNGBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [385, 0],
       "bounds": [15, 120],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutNGBlockFlow (positioned) DIV class='overlay'",
@@ -46,7 +40,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [28, 28, 0, 1]
+        [43, 43, 0, 1]
       ]
     },
     {
@@ -56,16 +50,6 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
-      ]
-    },
-    {
-      "id": 3,
-      "parent": 2,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [18, 10, 0, 1]
       ]
     }
diff --git a/third_party/blink/web_tests/compositing/iframes/iframe-size-from-zero-expected.txt b/third_party/blink/web_tests/compositing/iframes/iframe-size-from-zero-expected.txt
index dd60a9c..5f09dd6 100644
--- a/third_party/blink/web_tests/compositing/iframes/iframe-size-from-zero-expected.txt
+++ b/third_party/blink/web_tests/compositing/iframes/iframe-size-from-zero-expected.txt
@@ -7,29 +7,24 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME id='iframe' class='expanded'",
-      "bounds": [330, 180],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [285, 230],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutNGBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [285, 0],
       "bounds": [15, 150],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutNGBlockFlow (positioned) DIV class='overlay'",
@@ -45,7 +40,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [28, 28, 0, 1]
+        [43, 43, 0, 1]
       ]
     },
     {
@@ -55,16 +50,6 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
-      ]
-    },
-    {
-      "id": 3,
-      "parent": 2,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [18, 10, 0, 1]
       ]
     }
diff --git a/third_party/blink/web_tests/compositing/iframes/overlapped-iframe-expected.txt b/third_party/blink/web_tests/compositing/iframes/overlapped-iframe-expected.txt
index 6e665fd..5f09dd6 100644
--- a/third_party/blink/web_tests/compositing/iframes/overlapped-iframe-expected.txt
+++ b/third_party/blink/web_tests/compositing/iframes/overlapped-iframe-expected.txt
@@ -7,30 +7,24 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME id='parent-iframe'",
-      "position": [-30, -30],
-      "bounds": [390, 240],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [285, 230],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutNGBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [285, 0],
       "bounds": [15, 150],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutNGBlockFlow (positioned) DIV class='overlay'",
@@ -46,7 +40,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [28, 28, 0, 1]
+        [43, 43, 0, 1]
       ]
     },
     {
@@ -56,16 +50,6 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
-      ]
-    },
-    {
-      "id": 3,
-      "parent": 2,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [18, 10, 0, 1]
       ]
     }
diff --git a/third_party/blink/web_tests/compositing/iframes/overlapped-iframe-iframe-expected.txt b/third_party/blink/web_tests/compositing/iframes/overlapped-iframe-iframe-expected.txt
index c33c145..ce45a70 100644
--- a/third_party/blink/web_tests/compositing/iframes/overlapped-iframe-iframe-expected.txt
+++ b/third_party/blink/web_tests/compositing/iframes/overlapped-iframe-iframe-expected.txt
@@ -7,10 +7,6 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame (positioned) IFRAME",
-      "bounds": [304, 304]
-    },
-    {
       "name": "LayoutView #document",
       "bounds": [300, 300],
       "contentsOpaqueForText": true,
diff --git a/third_party/blink/web_tests/compositing/iframes/overlapped-nested-iframes-expected.txt b/third_party/blink/web_tests/compositing/iframes/overlapped-nested-iframes-expected.txt
index 7eba977..6219fb3 100644
--- a/third_party/blink/web_tests/compositing/iframes/overlapped-nested-iframes-expected.txt
+++ b/third_party/blink/web_tests/compositing/iframes/overlapped-nested-iframes-expected.txt
@@ -8,62 +8,42 @@
       "transform": 1
     },
     {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [284, 204],
+      "name": "LayoutView #document",
+      "bounds": [280, 200],
       "transform": 2
     },
     {
       "name": "LayoutView #document",
-      "bounds": [280, 200],
+      "bounds": [250, 170],
+      "contentsOpaqueForText": true,
+      "backgroundColor": "#C0C0C0",
       "transform": 3
     },
     {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [252, 172],
+      "name": "LayoutNGBlockFlow DIV id='iframe-content' class='box'",
+      "bounds": [210, 210],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
       "transform": 4
     },
     {
       "name": "LayoutView #document",
-      "bounds": [250, 170],
-      "contentsOpaqueForText": true,
-      "backgroundColor": "#C0C0C0",
+      "bounds": [280, 200],
       "transform": 5
     },
     {
-      "name": "LayoutNGBlockFlow DIV id='iframe-content' class='box'",
-      "bounds": [210, 210],
-      "contentsOpaque": true,
-      "backgroundColor": "#0000FF",
-      "transform": 6
-    },
-    {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [284, 204],
-      "transform": 7
-    },
-    {
-      "name": "LayoutView #document",
-      "bounds": [280, 200],
-      "transform": 8
-    },
-    {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [252, 172],
-      "transform": 9
-    },
-    {
       "name": "LayoutView #document",
       "bounds": [250, 170],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 10
+      "transform": 6
     },
     {
       "name": "LayoutNGBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 11
+      "transform": 7
     },
     {
       "name": "LayoutNGBlockFlow (positioned) DIV id='banner'",
@@ -94,7 +74,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [20, 150, 0, 1]
+        [22, 152, 0, 1]
       ]
     },
     {
@@ -104,7 +84,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [2, 2, 0, 1]
+        [9, 9, 0, 1]
       ]
     },
     {
@@ -114,17 +94,17 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [8, 8, 0, 1]
+        [18, 10, 0, 1]
       ]
     },
     {
       "id": 5,
-      "parent": 4,
+      "parent": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [1, 1, 0, 1]
+        [22, 376, 0, 1]
       ]
     },
     {
@@ -134,52 +114,12 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [18, 10, 0, 1]
+        [9, 9, 0, 1]
       ]
     },
     {
       "id": 7,
-      "parent": 1,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [20, 374, 0, 1]
-      ]
-    },
-    {
-      "id": 8,
-      "parent": 7,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [2, 2, 0, 1]
-      ]
-    },
-    {
-      "id": 9,
-      "parent": 8,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [8, 8, 0, 1]
-      ]
-    },
-    {
-      "id": 10,
-      "parent": 9,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [1, 1, 0, 1]
-      ]
-    },
-    {
-      "id": 11,
-      "parent": 10,
+      "parent": 6,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/blink/web_tests/compositing/iframes/scrolling-iframe-expected.txt b/third_party/blink/web_tests/compositing/iframes/scrolling-iframe-expected.txt
index c6dc8a9..5011806c 100644
--- a/third_party/blink/web_tests/compositing/iframes/scrolling-iframe-expected.txt
+++ b/third_party/blink/web_tests/compositing/iframes/scrolling-iframe-expected.txt
@@ -7,42 +7,36 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME id='parent-iframe'",
-      "position": [-30, -30],
-      "bounds": [390, 240],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [508, 608],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "LayoutNGBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [200, 200],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 4
+      "transform": 3
     },
     {
       "name": "ContentsLayer for Horizontal Scrollbar Layer",
       "position": [0, 135],
       "bounds": [285, 15],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [285, 0],
       "bounds": [15, 135],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "Scroll Corner Layer",
       "position": [285, 135],
       "bounds": [15, 15],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutNGBlockFlow (positioned) DIV class='overlay'",
@@ -58,7 +52,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [28, 28, 0, 1]
+        [43, 43, 0, 1]
       ]
     },
     {
@@ -68,7 +62,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
+        [-80, -80, 0, 1]
       ]
     },
     {
@@ -78,16 +72,6 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [-80, -80, 0, 1]
-      ]
-    },
-    {
-      "id": 4,
-      "parent": 3,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [108, 100, 0, 1]
       ]
     }
diff --git a/third_party/blink/web_tests/compositing/overflow/border-radius-composited-subframe-expected.png b/third_party/blink/web_tests/compositing/overflow/border-radius-composited-subframe-expected.png
index 0734fb1..6b63616 100644
--- a/third_party/blink/web_tests/compositing/overflow/border-radius-composited-subframe-expected.png
+++ b/third_party/blink/web_tests/compositing/overflow/border-radius-composited-subframe-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/compositing/rtl/rtl-iframe-absolute-expected.txt b/third_party/blink/web_tests/compositing/rtl/rtl-iframe-absolute-expected.txt
index 39d25c02..0557b9d 100644
--- a/third_party/blink/web_tests/compositing/rtl/rtl-iframe-absolute-expected.txt
+++ b/third_party/blink/web_tests/compositing/rtl/rtl-iframe-absolute-expected.txt
@@ -7,10 +7,6 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame (positioned) IFRAME",
-      "bounds": [400, 400]
-    },
-    {
       "name": "LayoutView #document",
       "bounds": [400, 400],
       "contentsOpaqueForText": true,
diff --git a/third_party/blink/web_tests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt b/third_party/blink/web_tests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt
index 6f417cf..19c34174 100644
--- a/third_party/blink/web_tests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt
+++ b/third_party/blink/web_tests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt
@@ -7,10 +7,6 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame (positioned) IFRAME",
-      "bounds": [400, 400]
-    },
-    {
       "name": "Scrolling Contents Layer",
       "position": [15, 0],
       "bounds": [1000, 1000],
diff --git a/third_party/blink/web_tests/compositing/rtl/rtl-iframe-fixed-expected.txt b/third_party/blink/web_tests/compositing/rtl/rtl-iframe-fixed-expected.txt
index 39d25c02..0557b9d 100644
--- a/third_party/blink/web_tests/compositing/rtl/rtl-iframe-fixed-expected.txt
+++ b/third_party/blink/web_tests/compositing/rtl/rtl-iframe-fixed-expected.txt
@@ -7,10 +7,6 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame (positioned) IFRAME",
-      "bounds": [400, 400]
-    },
-    {
       "name": "LayoutView #document",
       "bounds": [400, 400],
       "contentsOpaqueForText": true,
diff --git a/third_party/blink/web_tests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt b/third_party/blink/web_tests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt
index 4756200..f9a60ea7 100644
--- a/third_party/blink/web_tests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt
+++ b/third_party/blink/web_tests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt
@@ -7,10 +7,6 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame (positioned) IFRAME",
-      "bounds": [400, 400]
-    },
-    {
       "name": "Scrolling Contents Layer",
       "position": [15, 0],
       "bounds": [1000, 1000],
diff --git a/third_party/blink/web_tests/compositing/rtl/rtl-iframe-relative-expected.txt b/third_party/blink/web_tests/compositing/rtl/rtl-iframe-relative-expected.txt
index b44d93f..c6fa9595 100644
--- a/third_party/blink/web_tests/compositing/rtl/rtl-iframe-relative-expected.txt
+++ b/third_party/blink/web_tests/compositing/rtl/rtl-iframe-relative-expected.txt
@@ -7,10 +7,6 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame (positioned) IFRAME",
-      "bounds": [400, 400]
-    },
-    {
       "name": "LayoutView #document",
       "bounds": [400, 400]
     },
diff --git a/third_party/blink/web_tests/css3/background/background-right-bottom-subpixel-position-expected.html b/third_party/blink/web_tests/css3/background/background-right-bottom-subpixel-position-expected.html
index ce16208..c783880 100644
--- a/third_party/blink/web_tests/css3/background/background-right-bottom-subpixel-position-expected.html
+++ b/third_party/blink/web_tests/css3/background/background-right-bottom-subpixel-position-expected.html
@@ -5,7 +5,7 @@
       .background1 {
         position: absolute;
         top: 20px;
-        left: 48px;
+        left: 49px;
         width: 35px;
         height: 40px;
         margin: 0px;
@@ -13,10 +13,11 @@
         background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAABkCAIAAADITs03AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AcUEzYUOm312wAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAATSURBVBjTY2BoYGBiYBjFgwQDAGNPAUcILSYcAAAAAElFTkSuQmCC");
         background-position: bottom right;
         background-repeat: no-repeat;
+        border: 1px solid gray;
       }
       .background2 {
         position: absolute;
-        top: 20px;
+        top: 21px;
         left: 100px;
         width: 40px;
         height: 35px;
@@ -25,6 +26,7 @@
         background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAABCAIAAAATs2rlAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AcVEwcj/DEwAwAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAOSURBVAjXY2RoYBiEAABLrgCCBjI+jgAAAABJRU5ErkJggg==");
         background-position: bottom right;
         background-repeat: no-repeat;
+        border: 1px solid gray;
       }
     </style>
   </head>
diff --git a/third_party/blink/web_tests/css3/background/background-right-bottom-subpixel-position.html b/third_party/blink/web_tests/css3/background/background-right-bottom-subpixel-position.html
index 10a0a2a..1497a35fc 100644
--- a/third_party/blink/web_tests/css3/background/background-right-bottom-subpixel-position.html
+++ b/third_party/blink/web_tests/css3/background/background-right-bottom-subpixel-position.html
@@ -13,6 +13,7 @@
         background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAABkCAIAAADITs03AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AcUEzYUOm312wAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAATSURBVBjTY2BoYGBiYBjFgwQDAGNPAUcILSYcAAAAAElFTkSuQmCC");
         background-position: bottom right;
         background-repeat: no-repeat;
+        border: 1px solid gray;
       }
       .background2 {
         position: absolute;
@@ -25,6 +26,7 @@
         background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAABCAIAAAATs2rlAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AcVEwcj/DEwAwAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAOSURBVAjXY2RoYBiEAABLrgCCBjI+jgAAAABJRU5ErkJggg==");
         background-position: bottom right;
         background-repeat: no-repeat;
+        border: 1px solid gray;
       }
     </style>
   </head>
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 074cc129..94080cc 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
@@ -495,6 +495,13 @@
        null,
        {}
       ]
+     ],
+     "Node-cloneNode-on-inactive-document-crash.html": [
+      "cbd7a1e6a500e5671c1e0a71c5dcb963cab727ba",
+      [
+       null,
+       {}
+      ]
      ]
     },
     "svg-insert-crash.html": [
@@ -627,6 +634,26 @@
        ]
       }
      },
+     "scripting-1": {
+      "the-template-element": {
+       "template-element": {
+        "template-content-in-inactive-document-crash.html": [
+         "66c564c77a513f9f4946e38b0729ffcd744918a9",
+         [
+          null,
+          {}
+         ]
+        ],
+        "template-content-move-to-inactive-document-crash.html": [
+         "89c56d166339a3b707cd5cd3bfd6d0924db38272",
+         [
+          null,
+          {}
+         ]
+        ]
+       }
+      }
+     },
      "text-level-semantics": {
       "the-a-element": {
        "a-click-handler-with-null-browsing-context-crash.html": [
@@ -51585,6 +51612,32 @@
        {}
       ]
      ],
+     "flex-minimum-height-flex-items-023.html": [
+      "0e3e8d68117b9c4ccab1f960f37685bfe3c6004d",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square-only.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "flex-minimum-height-flex-items-024.html": [
+      "37052f7ec345e8e420a805b1bcada3b5a09211d5",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square-only.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "flex-minimum-width-flex-items-001.xht": [
       "cd18483ba414160c46e30bc282dec0c2fcd2f418",
       [
@@ -97604,6 +97657,45 @@
        {}
       ]
      ],
+     "text-decoration-thickness-fixed.html": [
+      "d5c388a5570c34b8c4527ba27998341be30404e6",
+      [
+       null,
+       [
+        [
+         "/css/css-text-decor/reference/text-decoration-thickness-fixed-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "text-decoration-thickness-from-font-variable.html": [
+      "025f910e1248cd9b2bb7ecdf31464d6fe624d8e9",
+      [
+       null,
+       [
+        [
+         "/css/css-text-decor/reference/text-decoration-thickness-from-font-variable-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "text-decoration-thickness-ink-skip-dilation.html": [
+      "e6bdd616cc519d302d26ce58bd063867b895cf09",
+      [
+       null,
+       [
+        [
+         "/css/css-text-decor/reference/text-decoration-thickness-ink-skip-dilation-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "text-decoration-thickness-linethrough-001.html": [
       "6fd8383d062960e5056a1e755eafdd95e23e0f88",
       [
@@ -140274,6 +140366,19 @@
          {}
         ]
        ],
+       "tr-transform-and-will-change.html": [
+        "0f37d635a59e7cac0abed273c8256b75166a7b35",
+        [
+         null,
+         [
+          [
+           "/html/rendering/non-replaced-elements/tables/tr-transform-and-will-change-ref.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
        "transformed-tbody-tr-collapsed-border.html": [
         "5f131e6658ae1bc7f013974d6975122d5cba2c97",
         [
@@ -141040,6 +141145,19 @@
        ]
       },
       "embedded-content": {
+       "cross-domain-iframe.sub.html": [
+        "973da08418b5a273d630af85939fe92b57221be5",
+        [
+         null,
+         [
+          [
+           "/html/rendering/replaced-elements/embedded-content/cross-domain-iframe.sub-ref.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
        "object-fallback-text-decoration.html": [
         "89657ef8a2dd6be764768388a8d57d994cc0fdb3",
         [
@@ -141434,6 +141552,32 @@
          ],
          {}
         ]
+       ],
+       "select-size-001.html": [
+        "ad4055415d526f0e2d2d25fed5c0c152cdda8c78",
+        [
+         null,
+         [
+          [
+           "/html/rendering/widgets/the-select-element/select-size-ref.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
+       "select-size-002.html": [
+        "0838e7a3c67b734202ed4fde1cc5e59e4d6d3498",
+        [
+         null,
+         [
+          [
+           "/html/rendering/widgets/the-select-element/select-size-ref.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
        ]
       }
      }
@@ -144003,6 +144147,45 @@
         {}
        ]
       ],
+      "frac-invalid-2.html": [
+       "4bd72c760761ca3ced56a2b6293c93716e1edaf6",
+       [
+        null,
+        [
+         [
+          "/mathml/presentation-markup/fractions/frac-invalid-2-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "frac-invalid-3.html": [
+       "056e9b6b716808be9ea0e22be9f4a9fdbf00cfb5",
+       [
+        null,
+        [
+         [
+          "/mathml/presentation-markup/fractions/frac-invalid-3-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "frac-invalid.html": [
+       "cefae791bad0350deff33cbad0e1e2488935e7ca",
+       [
+        null,
+        [
+         [
+          "/mathml/presentation-markup/fractions/frac-invalid-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "frac-legacy-bevelled-attribute.tentative.html": [
        "1f14044106e0c311eb68b3102d6b12767d2b5c4f",
        [
@@ -152854,13 +153037,13 @@
     ],
     "idl": {
      "idlharness.tentative.https.window-expected.txt": [
-      "2f344a2b102c49188eed28ded52db11c8cf7ac82",
+      "64d419afee91c46136fe4110b9bd89a0a765998e",
       []
      ]
     },
     "resources": {
      "bluetooth-fake-devices.js": [
-      "6ac2380df0e88a05a8e035d16368404d9a4b5ff2",
+      "fdb08379d05179b502ce4d769dee9138aa9730d7",
       []
      ],
      "bluetooth-scanning-helpers.js": [
@@ -157044,7 +157227,7 @@
       []
      ],
      "304.py": [
-      "2fc83b9aea3879320a76d7df44eca8f16f050bb2",
+      "8fdf29a313203d919e7753c8114c5ee9b282382d",
       []
      ],
      "access-control-expose-headers.json": [
@@ -157052,15 +157235,15 @@
       []
      ],
      "cache-304.py": [
-      "7acdfd69768200df10981bb31c97634800c77441",
+      "41cd16d9a2d5c016873c0de55978ffd91aa73f76",
       []
      ],
      "checkandremove.py": [
-      "f713d990afcddb0cf000499c6b9a2e37b17481d0",
+      "5cd7868199f32e3c8e3529172785267a1ad6ee3d",
       []
      ],
      "cors-cookie.py": [
-      "061563e4f2078c44f9aad3a3e8d87b453b1af1fb",
+      "ee42494ad053e9462e6bfe1982f77e0c8442e984",
       []
      ],
      "cors-headers.asis": [
@@ -157068,11 +157251,11 @@
       []
      ],
      "cors-makeheader.py": [
-      "eab35eedfc9afbbf3896c31c473fb56468e2eaa8",
+      "8d6db74e46d57624a9e86223e7bbdabfd1d10cf9",
       []
      ],
      "expose-headers.py": [
-      "c350b3b87be64ee40e4d9bd033caae7f3f29953d",
+      "e9de401cf2a5fb88efa77905c95cef5aa474949d",
       []
      ],
      "image-tainting-checker.sub.html": [
@@ -157080,7 +157263,7 @@
       []
      ],
      "preflight.py": [
-      "978e97c5d1e9cabef26f1acb831b799429ad1e70",
+      "d8bce26d280a12a30bb83d9e25f9108a9cd86624",
       []
      ],
      "remote-xhrer.html": [
@@ -157088,7 +157271,7 @@
       []
      ],
      "status.py": [
-      "96950dae4fd39375ca682bd3740fbaf6e691922a",
+      "5d37e7a038277121cd0ce44b9c161e4c9360e428",
       []
      ]
     },
@@ -161240,7 +161423,7 @@
       []
      ],
      "KeyframeEffect-getKeyframes.tentative-expected.txt": [
-      "8c956d51cc1755f87a3eedaff873b50407c4d470",
+      "9dc46918c17373ca1cb2b8cd6816750155280697",
       []
      ],
      "META.yml": [
@@ -161299,7 +161482,7 @@
        []
       ],
       "testcommon.js": [
-       "e26a7a1858ab9e4d404fa9fb76b4a9f4c4f13572",
+       "a7575b158e3e3527963b61a4a0f2ad9a202aa66c",
        []
       ]
      }
@@ -181752,10 +181935,22 @@
        "4e7db88ce5b41e28aa43fc339c35438855abb928",
        []
       ],
+      "text-decoration-thickness-fixed-ref.html": [
+       "27cc6dada1c1cce56565a29c77df0d519a757d5b",
+       []
+      ],
+      "text-decoration-thickness-from-font-variable-ref.html": [
+       "4ecbec044f0d43219f6c25ecb0df1a6b3eeaac5b",
+       []
+      ],
       "text-decoration-thickness-green-rect-ref.html": [
        "14d1219001c85dcf785e648db81ca5d6fc6d4301",
        []
       ],
+      "text-decoration-thickness-ink-skip-dilation-ref.html": [
+       "1b02fda550c8ec62e439dc9135571fe1b72ca10d",
+       []
+      ],
       "text-decoration-thickness-scroll-001-ref.html": [
        "394811468fea2d4e7daaffad19742cd8e206a8bd",
        []
@@ -181910,6 +182105,14 @@
        "cbca09812ee3d6f687b2e1fba0aebbe84d891b0c",
        []
       ],
+      "UnderlineTest-Thick.ttf": [
+       "0088b6fdd76c28a6422a7a07c64893b310c5b99b",
+       []
+      ],
+      "UnderlineTest-Thin.ttf": [
+       "ba1c6d17cca2537efca9185d12be3953004224a5",
+       []
+      ],
       "UnderlineTest-VF.ttf": [
        "2ac4de16f7e301257e3ee38388e302ee67850d33",
        []
@@ -187819,30 +188022,6 @@
       "2f84a0d554569cea4c707b04371f3f14058e96fe",
       []
      ],
-     "HTMLLinkElement-disabled-001-expected.txt": [
-      "b078ddb22ee2fcb6815eeac6a5146a2ddef104c8",
-      []
-     ],
-     "HTMLLinkElement-disabled-001.tentative-expected.txt": [
-      "b078ddb22ee2fcb6815eeac6a5146a2ddef104c8",
-      []
-     ],
-     "HTMLLinkElement-disabled-002-expected.txt": [
-      "176385c5078ade77d21160f0987f07c07433b485",
-      []
-     ],
-     "HTMLLinkElement-disabled-002.tentative-expected.txt": [
-      "176385c5078ade77d21160f0987f07c07433b485",
-      []
-     ],
-     "HTMLLinkElement-disabled-007-expected.txt": [
-      "4fac01798a1627557110ff1df67ab2fa0f96b6b6",
-      []
-     ],
-     "HTMLLinkElement-disabled-007.tentative-expected.txt": [
-      "4fac01798a1627557110ff1df67ab2fa0f96b6b6",
-      []
-     ],
      "HTMLLinkElement-disabled-alternate-ref.html": [
       "5d87bfdaf5b0533f2ea7088a870ca45474d065f4",
       []
@@ -192015,6 +192194,324 @@
      []
     ]
    },
+   "docs": {
+    "META.yml": [
+     "978b5c85721c28f267ec21ceb620017514441385",
+     []
+    ],
+    "Makefile": [
+     "1b7fe8e8f59277413c00cfe4d7080aa97eb449a0",
+     []
+    ],
+    "README.md": [
+     "a753462429d6cd460affa993e1a0db8cd3ec9fcd",
+     []
+    ],
+    "__init__.py": [
+     "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
+     []
+    ],
+    "admin": {
+     "index.md": [
+      "98725bfa31b90162ae7fe9a3f381a8d9494db09c",
+      []
+     ]
+    },
+    "assets": {
+     "commit-directly.png": [
+      "d02eef4ab505fa1b5a9b6661598f8e9d487b275f",
+      []
+     ],
+     "commitbtn.png": [
+      "20084890750b2fedee782cbccd6e14c6d643276d",
+      []
+     ],
+     "createpr.png": [
+      "4403a95c146c1aaba697a5198852548d948a5461",
+      []
+     ],
+     "custom.css": [
+      "58a982579f06c2c7093e4847a64d91c9722dd946",
+      []
+     ],
+     "files-changed.png": [
+      "7472edcb965c98e414e1be6412f0ed58afbe0f6b",
+      []
+     ],
+     "forkbtn.png": [
+      "f33cdd05aca78995e10798d616a3bdb77ca12296",
+      []
+     ],
+     "gh-fork-ribbon.scss": [
+      "c81530bfdb6688a1c0f2614b01c69dead7032aa9",
+      []
+     ],
+     "more-commits.png": [
+      "0d6b1a979486bfac4d8030e6d83cdeaaad08b2da",
+      []
+     ],
+     "pencil-icon.png": [
+      "ea347dd43b8fbcb0885ce5a338752a513df8c4a0",
+      []
+     ],
+     "praccepteddelete.png": [
+      "efb8e0798bd9e4468b11f877e3ca2cef9d4e57e4",
+      []
+     ],
+     "pullrequestbtn.png": [
+      "07d9c6a2e94122c94ae4d3802e09d9bbaea3296d",
+      []
+     ],
+     "reftest-tutorial-test-screenshot.png": [
+      "8d882822e1274124249be51cc2af26be0c23f340",
+      []
+     ],
+     "testharness-tutorial-test-screenshot-1.png": [
+      "c469e94a553c2f780dfd297bf127990674b142cc",
+      []
+     ],
+     "testharness-tutorial-test-screenshot-2.png": [
+      "612eda54487bd8e8808e8c8a3e87d0f221e55d00",
+      []
+     ],
+     "web-platform.png": [
+      "8547f491835ea2b11c69ff66f834ebc747af7fab",
+      []
+     ]
+    },
+    "commands.json": [
+     "55408d83dbc590f530cee36f7d2012b2e36aa2cd",
+     []
+    ],
+    "conf.py": [
+     "89f30a02a336d29c20a530a1d277586aa409da46",
+     []
+    ],
+    "frontend.py": [
+     "4b97e2e09589cbda5e147b7b55c5291f80f80d1a",
+     []
+    ],
+    "index.md": [
+     "419c99aca9d78c259235dbaa9e8ab662930ffb81",
+     []
+    ],
+    "intro-video-transcript.md": [
+     "b43ebf728fc2340420827be04e17b884015daf1f",
+     []
+    ],
+    "make.bat": [
+     "49607bb0ae936d9d8df9b1d1f16ce72e918108bc",
+     []
+    ],
+    "requirements.txt": [
+     "a9ddeecfe573825febb48afcd16ce4bc02b696ff",
+     []
+    ],
+    "reviewing-tests": {
+     "checklist.md": [
+      "0e50843f289bfad232723065f41442ba0b241713",
+      []
+     ],
+     "email.md": [
+      "55bbf4436726163432837909db30bf57d570b865",
+      []
+     ],
+     "git.md": [
+      "b74b4b77ae4c9124bab579b8270071645ffa2f57",
+      []
+     ],
+     "index.md": [
+      "e313f84596da648a111efd5f817737e125829b6c",
+      []
+     ],
+     "reverting.md": [
+      "277ccb047abb1b54448a3be76722412e0ddb1979",
+      []
+     ]
+    },
+    "running-tests": {
+     "android_webview.md": [
+      "4a86814fdf71b69e7b6b89d684a208131852cdbe",
+      []
+     ],
+     "chrome.md": [
+      "c56d3c56f846f0318e452765192df27beb05e2b9",
+      []
+     ],
+     "chrome_android.md": [
+      "a216a8a68b8f7287a0a9295c59fdeeac4d2ddd65",
+      []
+     ],
+     "command-line-arguments.md": [
+      "598c9da2a10514062ee3ea06d5c5335677763e32",
+      []
+     ],
+     "custom-runner.md": [
+      "4e860edbb21193a82d7333541eb55ada124c82f1",
+      []
+     ],
+     "from-ci.md": [
+      "9ea142bb4ba4a5b6f4bb7f0da7c4d29cf932486b",
+      []
+     ],
+     "from-local-system.md": [
+      "8c71e535baa907f1ef86641ee6211adb7d0c2423",
+      []
+     ],
+     "from-web.md": [
+      "fae4c961743f81e5d5cf8a35187a86b02af46fd7",
+      []
+     ],
+     "index.md": [
+      "17b361dde8f93880d9f8951b48020e521f55ecd6",
+      []
+     ],
+     "safari.md": [
+      "eed52254718922b000abd30273a50d56ce84d35a",
+      []
+     ],
+     "webkitgtk_minibrowser.md": [
+      "7aac81e5fce660db84969f9c0a7cae429a257207",
+      []
+     ]
+    },
+    "test-suite-design.md": [
+     "6a104e2f1d42fda1111124022dd7d94aaea3a598",
+     []
+    ],
+    "wpt_lint_rules.py": [
+     "a5eed507b5e774c37d5081046173ca5629bb7c16",
+     []
+    ],
+    "writing-tests": {
+     "ahem.md": [
+      "30a3fcde26cd48910549c23dc0cd0fbc05e7b3c7",
+      []
+     ],
+     "assumptions.md": [
+      "5afa41612120ff0feec19b01102e8cd8128c2652",
+      []
+     ],
+     "crashtest.md": [
+      "0166bdeb752ccccb6fdeb6860fe9286936b7bf01",
+      []
+     ],
+     "css-metadata.md": [
+      "9d8ebeddff2839265d38020fae519bd678d7b473",
+      []
+     ],
+     "css-user-styles.md": [
+      "9dac5af651bfb2d0344ddf15d9867551665ad782",
+      []
+     ],
+     "file-names.md": [
+      "57a91f0d83391b9a4a32bed5c263090131fab1d8",
+      []
+     ],
+     "general-guidelines.md": [
+      "531c9a5e2e1f4f78dc2405ec12de241edf19174a",
+      []
+     ],
+     "github-intro.md": [
+      "44b6828ad3c83f1510c92ffab3d5b561e47469ce",
+      []
+     ],
+     "h2tests.md": [
+      "c13295e1fe668af1ed9561463b2ec18719f8deb6",
+      []
+     ],
+     "idlharness.md": [
+      "13e1dc03fef758e710ec2046395cdad4a5a8117f",
+      []
+     ],
+     "index.md": [
+      "90a67c21fce2d1546544c0540d3158fd5bf16a26",
+      []
+     ],
+     "lint-tool.md": [
+      "f9caca35fef670aa2c22f3eec7cc9bfcbaee199a",
+      []
+     ],
+     "making-a-testing-plan.md": [
+      "520c5a32e0705e9a692a96f2e6ac998a191acf4b",
+      []
+     ],
+     "manual.md": [
+      "122a22b3f367d36d749c567c62c09ae9454c2aee",
+      []
+     ],
+     "print-reftests.md": [
+      "62a037da124406872a3414c4719dbe1ec46a4e95",
+      []
+     ],
+     "python-handlers": {
+      "index.md": [
+       "e3be1485bf0e6a07af647000c6dee0d69b79a2dc",
+       []
+      ]
+     },
+     "reftest-tutorial.md": [
+      "a51430942ce8853f788715eb2f548435406f520a",
+      []
+     ],
+     "reftests.md": [
+      "9f3165ced4c4e754680124a1e8722af15b9893eb",
+      []
+     ],
+     "rendering.md": [
+      "e17b6ef879716ef49cc1ff21bd1aa6923282afaa",
+      []
+     ],
+     "server-features.md": [
+      "980a27d3d02f01b04ad9ff164b2da61eef8478d9",
+      []
+     ],
+     "server-pipes.md": [
+      "4f4011a6c2148dc91358e89f31f234a6fd82d7b8",
+      []
+     ],
+     "submission-process.md": [
+      "c6268f9b11da904b000f121d558e496d3da6dfa3",
+      []
+     ],
+     "test-templates.md": [
+      "e8f4bfe77f4c7d142345e02792f2128d25c40f54",
+      []
+     ],
+     "testdriver-extension-tutorial.md": [
+      "a2d42e008c1bca17cdf701288e6b0b37211f2752",
+      []
+     ],
+     "testdriver.md": [
+      "63608a71c27831cdae45fef5c85fad8f0d792c82",
+      []
+     ],
+     "testharness-api.md": [
+      "8160ca298ed3dcac1fbb2f9c3153e27260d758c1",
+      []
+     ],
+     "testharness-tutorial.md": [
+      "dceb674ac4d643f420a0fdd84da2e37051f4b474",
+      []
+     ],
+     "testharness.md": [
+      "1e9772a401796da1a9a15f1fea9958843c64dc7e",
+      []
+     ],
+     "tools.md": [
+      "0a9a7dcfd59203260dd2411895ee49f2d85fad80",
+      []
+     ],
+     "visual.md": [
+      "a8ae53d0715be1ddcf9a2033572cb2d4e92b91f1",
+      []
+     ],
+     "wdspec.md": [
+      "16bdb9365f002c471d0c7c90147ed284624a9556",
+      []
+     ]
+    }
+   },
    "document-policy": {
     "echo-policy-nested.html": [
      "d572dcb0465843c3d694d808c8bc883cd54fbf89",
@@ -194850,7 +195347,7 @@
       []
      ],
      "event-timing-test-utils.js": [
-      "d01ff1d27d402ddf42f9856f25f37db27b93176b",
+      "749cfe3c19d1b3c65da1530bd339190b0566f429",
       []
      ],
      "slow-image.py": [
@@ -194955,6 +195452,10 @@
       "2b74bf66a286ff65b386662412018002c762dee2",
       []
      ],
+     "last-event-id2.py": [
+      "4f133d707d1f72f2717aec14423b4c613498ba03",
+      []
+     ],
      "message.py": [
       "6d04b1fbe40dfbdf16faf2171ef5527a85f3b951",
       []
@@ -195029,24 +195530,6 @@
      []
     ],
     "experimental-features": {
-     "lazyload": {
-      "lazyload-disabled-image-tentative.sub.html.headers": [
-       "7974815fc9cc069a3890cec9d09d1c6b3e3f9908",
-       []
-      ],
-      "lazyload-disabled-tentative.sub.html.headers": [
-       "d0bac47e01a7e903d78ffab7b73838f0852852d6",
-       []
-      ],
-      "lazyload-enabled-tentative.sub.html.headers": [
-       "83b744e2bc4e09b771c7997fc044802f77f65407",
-       []
-      ],
-      "loading-frame-default-eager-disabled-tentative.sub.html.headers": [
-       "8cba4d2df9c22809641984a0071aae947b4f91ae",
-       []
-      ]
-     },
      "resources": {
       "async-script.js": [
        "3c0ee6d02343891b0234f31c0fb229929ae1b24b",
@@ -200653,6 +201136,42 @@
       "3f080c82d25de71d899d3b3011afcc3c553fb2a2",
       []
      ],
+     "access-reporting": {
+      "META.yml": [
+       "0db28208a6d9731570398b1d83f8bf1ba32a4dec",
+       []
+      ],
+      "openee-accessed_openee-coop-ro.https-expected.txt": [
+       "e29dca833eb1206b52e35a2fafbf77badeb4a6e3",
+       []
+      ],
+      "openee-accessed_openee-coop.https-expected.txt": [
+       "e29dca833eb1206b52e35a2fafbf77badeb4a6e3",
+       []
+      ],
+      "opener-accessed_openee-coop-ro.https-expected.txt": [
+       "e29dca833eb1206b52e35a2fafbf77badeb4a6e3",
+       []
+      ],
+      "opener-accessed_openee-coop.https-expected.txt": [
+       "e29dca833eb1206b52e35a2fafbf77badeb4a6e3",
+       []
+      ],
+      "resources": {
+       "dispatcher.js": [
+        "d0184d579d3b9d36c77db9fdbbb6e2dfaf06891c",
+        []
+       ],
+       "dispatcher.py": [
+        "67b8cc3d3dde0ad4272e2000fe75efab214d9d9f",
+        []
+       ],
+       "executor.html": [
+        "3b10da03739ed22b0295c82837951a30cb0ec666",
+        []
+       ]
+      }
+     },
      "blob-popup.https-expected.txt": [
       "0021a4702e1ebd39dd9ca8ed9ed54fb8bdaf8fa5",
       []
@@ -205495,6 +206014,10 @@
         "2b0f9e445c21c527557f61d6ee117b495c7db153",
         []
        ],
+       "tr-transform-and-will-change-ref.html": [
+        "2cbcd6a347cc39c994031e5a7dfc5f9e13d6684b",
+        []
+       ],
        "transformed-tbody-tr-collapsed-border-ref.html": [
         "2f313f3395ff237c131fdf7646b07541734e5dad",
         []
@@ -205755,6 +206278,10 @@
        ]
       },
       "embedded-content": {
+       "cross-domain-iframe.sub-ref.html": [
+        "a3579eee74c242c156055eafff9684f126cf8ae5",
+        []
+       ],
        "object-fallback-text-decoration-ref.html": [
         "9481e80ac81b14cc7c4a044b16cc3e8cf5d547e6",
         []
@@ -205910,6 +206437,10 @@
        "option-label-ref.html": [
         "3dd07b8dc2b4778d7f2f2e69202d680902c7e838",
         []
+       ],
+       "select-size-ref.html": [
+        "fc3b3be6e55d23d56b33589511bcb3ee982ed289",
+        []
        ]
       }
      }
@@ -207259,10 +207790,6 @@
         "aa09bf93e1326d379228a5334b59fe1b7f06d35c",
         []
        ],
-       "image-loading-lazy-relevant-mutations-expected.txt": [
-        "e42073224a3b8f47e8803045d8703afbe5410b3d",
-        []
-       ],
        "image-loading-lazy-slow-aspect-ratio-ref.html": [
         "6de01a9b3bbf19567555af2524f8950abdfb2d81",
         []
@@ -211152,10 +211679,6 @@
      "e427ae8801a7863a59d9507d384e075e34bd4731",
      []
     ],
-    "CSS-Parser-API.idl": [
-     "57ee7b73678e66019dd864c553fd2f3f964bd562",
-     []
-    ],
     "DOM-Parsing.idl": [
      "5020be899425be9bb32b4592a53bce76f8d090af",
      []
@@ -211168,10 +211691,6 @@
      "8af2bbcf23821e34f95fe2cabdb3d3b3b91b3eb8",
      []
     ],
-    "InputDeviceCapabilities.idl": [
-     "cb5d2827e40554fdc43890bf52915c6a0efffbe3",
-     []
-    ],
     "META.yml": [
      "e624c12d5b7ee4335b5d355d6ea2e43993b7fdd5",
      []
@@ -211312,6 +211831,10 @@
      "c636e2e7d3771fa4d0fb0df06088885552da6e00",
      []
     ],
+    "css-parser-api.idl": [
+     "f3e586785dc2d5d86b489715e4981e517304e7e8",
+     []
+    ],
     "css-properties-values-api.idl": [
      "d8f54b1e15bc020ef101ab53626eee6985c63dcb",
      []
@@ -211432,6 +211955,10 @@
      "094f3f5cafe87a1f8dbbb004842715d8f552d0b4",
      []
     ],
+    "input-device-capabilities.idl": [
+     "86015b30dbda40866a945f0599d2e5db99b1d2ec",
+     []
+    ],
     "input-events.idl": [
      "5ddaae5b9d3db83caca699c847373e7deb421ac4",
      []
@@ -211633,7 +212160,7 @@
      []
     ],
     "scroll-animations.idl": [
-     "00d0bae68126aa67d6714694422a098100eb7e71",
+     "33fb59b026fb39e8254ad12a5ce01fd5ae753c38",
      []
     ],
     "secure-contexts.idl": [
@@ -211749,7 +212276,7 @@
      []
     ],
     "webdriver.idl": [
-     "00dc14858569e5039bcd3e82d96d5268237b2251",
+     "3ab991ba4e1b91c155944552332ddd9e4218b40d",
      []
     ],
     "webgl1.idl": [
@@ -211805,7 +212332,7 @@
      []
     ],
     "xhr.idl": [
-     "de478734ca96985e9868a1e64fbf617faa9c11e5",
+     "d3d0e5378d367110b2e75120877b7cb1e38babb5",
      []
     ],
     "xslt.tentative.idl": [
@@ -212166,6 +212693,18 @@
        "93d3e0162b6b634e012ac07915577bef38d46acb",
        []
       ],
+      "frac-invalid-2-ref.html": [
+       "5b1960db59238590ac93af5c123ab2bff1066716",
+       []
+      ],
+      "frac-invalid-3-ref.html": [
+       "7cb95acaf09c82060e2cd5a2b3ee9ef7e05b55b0",
+       []
+      ],
+      "frac-invalid-ref.html": [
+       "e1c44fea37edbafc3f8df11f2b18fa190fe8bd8c",
+       []
+      ],
       "frac-legacy-bevelled-attribute.tentative-ref.html": [
        "f0b355c7bd981ececd2ef2d6f0240898b45d11e5",
        []
@@ -212233,6 +212772,16 @@
        []
       ]
      },
+     "mpadded": {
+      "mpadded-001-expected.txt": [
+       "f652024378226e188c8f1ef011e64a059d2ea432",
+       []
+      ],
+      "mpadded-003-expected.txt": [
+       "2b658e2389a02b7c7cd17ccfb17c002ef832d2c8",
+       []
+      ]
+     },
      "mrow": {
       "dynamic-mrow-like-001-ref.html": [
        "2f823ba9550d1c5a2cac2fe5b4b3bc5867a1be75",
@@ -212726,6 +213275,10 @@
        "272e8b33ca70c691e127c68344d595eb4c0762ea",
        []
       ],
+      "dynamic-childlist-001-expected.txt": [
+       "66f5e05ee9fceb8b0200bc02d8288e2afd32eba5",
+       []
+      ],
       "href-click-1-ref.html": [
        "86952567c76f4b0f1c45ac8b03b34a93d0400163",
        []
@@ -214002,7 +214555,7 @@
       []
      ],
      "message-target.js": [
-      "b9c0e4f8565e647577cad859129257fa447bd8dc",
+      "423bcf42e16bdbc17fd4fc337d6bc070169eb983",
       []
      ],
      "messaging-blob-helpers.js": [
@@ -214022,11 +214575,11 @@
       []
      ],
      "opaque-origin-sandbox.html": [
-      "07301af1cfaf250e0da67de4021a86f12c7e42e8",
+      "70b5ac545b30a36f9418ac571cb77f25b31a6542",
       []
      ],
      "sandboxed-fs-test-helpers.js": [
-      "5f4f269d2242c2bac59136ff2cf99cbb18f639eb",
+      "3ec31436a0397ff4f7e8b8c83d504240e63bf4bd",
       []
      ],
      "test-helpers.js": [
@@ -217626,7 +218179,7 @@
       []
      ],
      "web-bluetooth-test.js": [
-      "fb6965c9f3840f6c129a5136adbcfa9365bb6b5e",
+      "b63658e2e753218d50508b41199fc6ff18711dbf",
       []
      ],
      "web-bluetooth-test.js.headers": [
@@ -217666,7 +218219,7 @@
       []
      ],
      "webxr-test.js": [
-      "adbb42eed8b70bef4c2786344fc24d90faf47bb8",
+      "bfe00679c8b599e5332f5c539c94b979975ee87c",
       []
      ],
      "webxr-test.js.headers": [
@@ -217878,6 +218431,20 @@
      "f52fddfbf134a724704b4ddc63dd27289bb6ebd2",
      []
     ],
+    "css": {
+     "animation-timeline-computed-expected.txt": [
+      "8ce545a7c55ea42b7946992eb38835499bdffb1a",
+      []
+     ],
+     "animation-timeline-in-keyframe-expected.txt": [
+      "0af056bbffc521c1ad6615ff3beed9d0a9a3bc0f",
+      []
+     ],
+     "animation-timeline-parsing-expected.txt": [
+      "dced00e4d2eeee96dd57875bc85268bef3d5dd3c",
+      []
+     ]
+    },
     "idlharness.window-expected.txt": [
      "3fa0605a4c7f21beb2428e3d09a6775c8bc2b4f0",
      []
@@ -217889,7 +218456,7 @@
      ]
     },
     "testcommon.js": [
-     "c7290f15836728a7ccd25f0caf624e6a06b264fc",
+     "d9fc153887c5fcbe839aeddb90f16d63a7bed868",
      []
     ]
    },
@@ -222693,12 +223260,12 @@
       "11190fc58d64491bae719f9ac91adb1e879886fb",
       []
      ],
-     "ci_tools_unittest.sh": [
-      "366dcf66de88e6ba29fc85c9697832eead9376c3",
+     "ci_tools_integration_test.sh": [
+      "7c37e7863e002db66c59009ae3d4360aaa717499",
       []
      ],
-     "ci_wpt.sh": [
-      "7c37e7863e002db66c59009ae3d4360aaa717499",
+     "ci_tools_unittest.sh": [
+      "366dcf66de88e6ba29fc85c9697832eead9376c3",
       []
      ],
      "ci_wptrunner_infrastructure.sh": [
@@ -222760,7 +223327,7 @@
       ],
       "tasks": {
        "test.yml": [
-        "318437a80ec3240721a17cc6253f241109038b64",
+        "3fae9eacaf121f383ef143d7be98efae2f0b6011",
         []
        ]
       },
@@ -222792,7 +223359,7 @@
         []
        ],
        "test_valid.py": [
-        "47cbc2e87bb80597dd980e9f98bc413b0416b552",
+        "acfe875d74d22695363cb0328aabcf18b6704d4e",
         []
        ]
       }
@@ -223003,7 +223570,7 @@
      []
     ],
     "requirements_mypy.txt": [
-     "988ffe848174f7215278c2c4019f924bed3a61f5",
+     "857c7886e18319b342488446563457052c0b6aad",
      []
     ],
     "runner": {
@@ -229962,7 +230529,7 @@
       []
      ],
      "keyframe-utils.js": [
-      "971e82ed81d6fef46a65f11ec66331a9f1954dfc",
+      "fdea1d8d93ca05ebd093e5a155f97896a2aed49f",
       []
      ],
      "timing-override.js": [
@@ -229983,7 +230550,7 @@
      ]
     },
     "testcommon.js": [
-     "1eb24f658c2348171b386f36dcc1b824ad236fbc",
+     "baa7550d66045e56d668f37fd4d349854f5e6753",
      []
     ],
     "timing-model": {
@@ -231511,7 +232078,7 @@
      []
     ],
     "RTCPeerConnection-getStats.https-expected.txt": [
-     "126a223e101d6eb1a56bf5d2e4e1aaef89590539",
+     "e2df6c1d7e8d35477ee6d1a6bdeb2343b4118188",
      []
     ],
     "RTCPeerConnection-helper.js": [
@@ -231523,7 +232090,7 @@
      []
     ],
     "RTCPeerConnection-mandatory-getStats.https-expected.txt": [
-     "1256301b7422386b9406b8fa81af5d148b72d6d5",
+     "e2df6c1d7e8d35477ee6d1a6bdeb2343b4118188",
      []
     ],
     "RTCPeerConnection-onnegotiationneeded-expected.txt": [
@@ -231579,7 +232146,7 @@
      []
     ],
     "RTCPeerConnection-track-stats.https-expected.txt": [
-     "bd8e8449e00bea6b07050accc890d99e8e61d4b2",
+     "e2df6c1d7e8d35477ee6d1a6bdeb2343b4118188",
      []
     ],
     "RTCPeerConnectionIceEvent-constructor-expected.txt": [
@@ -231599,7 +232166,7 @@
      []
     ],
     "RTCRtpReceiver-getStats.https-expected.txt": [
-     "002ae8027389e44ca60c1566a39b323f29efc7ef",
+     "e2df6c1d7e8d35477ee6d1a6bdeb2343b4118188",
      []
     ],
     "RTCRtpReceiver-getSynchronizationSources.https-expected.txt": [
@@ -231607,7 +232174,7 @@
      []
     ],
     "RTCRtpSender-getStats.https-expected.txt": [
-     "f7302af8c8a2720b5856d8ff7de1078090b11a9d",
+     "e2df6c1d7e8d35477ee6d1a6bdeb2343b4118188",
      []
     ],
     "RTCRtpSender-replaceTrack.https-expected.txt": [
@@ -231627,7 +232194,7 @@
      []
     ],
     "RTCStats-helper.js": [
-     "5cd7d2c9e0e1f6c5c10afe529be8489dec4dd5ad",
+     "7bebc2e7b19d70754533373f1dad0d2f003422e3",
      []
     ],
     "RTCTrackEvent-constructor-expected.txt": [
@@ -231672,6 +232239,10 @@
      "README.txt": [
       "8adbf6aa173949718a90bd54cc95361e1a8801ba",
       []
+     ],
+     "RTCPeerConnection-addStream.https-expected.txt": [
+      "e2df6c1d7e8d35477ee6d1a6bdeb2343b4118188",
+      []
      ]
     },
     "protocol": {
@@ -231680,7 +232251,7 @@
       []
      ],
      "crypto-suite.https-expected.txt": [
-      "1d818ac3e47dce64100cab6adab2f9ee1e48953f",
+      "e2df6c1d7e8d35477ee6d1a6bdeb2343b4118188",
       []
      ]
     },
@@ -231739,6 +232310,10 @@
     "META.yml": [
      "4ceee0664cbfb800ac8b410c295dde4c7009b024",
      []
+    ],
+    "RTCRtpSynchronizationSource-captureTimestamp-expected.txt": [
+     "e2df6c1d7e8d35477ee6d1a6bdeb2343b4118188",
+     []
     ]
    },
    "webrtc-identity": {
@@ -231809,7 +232384,7 @@
      []
     ],
     "getStats-remote-candidate-address-expected.txt": [
-     "a18cda03b56a2721c189b1e88bfe0df23984970c",
+     "e2df6c1d7e8d35477ee6d1a6bdeb2343b4118188",
      []
     ]
    },
@@ -235745,11 +236320,11 @@
      []
     ],
     "idlharness.any.sharedworker-expected.txt": [
-     "d6f6505a27696a1c2d74af34ec595d5487e422dc",
+     "70da516a8b653ce811154eabaa12db3999e70651",
      []
     ],
     "idlharness.any.worker-expected.txt": [
-     "d6f6505a27696a1c2d74af34ec595d5487e422dc",
+     "70da516a8b653ce811154eabaa12db3999e70651",
      []
     ],
     "no-utf16-json-expected.txt": [
@@ -250208,6 +250783,242 @@
         }
        ]
       ]
+     },
+     "watchAdvertisements": {
+      "abort-before-watchAdvertisements.https.window.js": [
+       "e1ac1fb136902244055e88f859d9d536bc58951c",
+       [
+        "bluetooth/device/watchAdvertisements/abort-before-watchAdvertisements.https.window.html",
+        {
+         "script_metadata": [
+          [
+           "script",
+           "/resources/testdriver.js"
+          ],
+          [
+           "script",
+           "/resources/testdriver-vendor.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-test.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-fake-devices.js"
+          ]
+         ]
+        }
+       ]
+      ],
+      "abort-pending-operation.https.window.js": [
+       "c1022ff4a9c1b8c57703a8ce5b8bdfa309b7d985",
+       [
+        "bluetooth/device/watchAdvertisements/abort-pending-operation.https.window.html",
+        {
+         "script_metadata": [
+          [
+           "script",
+           "/resources/testdriver.js"
+          ],
+          [
+           "script",
+           "/resources/testdriver-vendor.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-test.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-fake-devices.js"
+          ]
+         ]
+        }
+       ]
+      ],
+      "abort-signal-stops-events.https.window.js": [
+       "21b6883fee433a2a04c689ae82c9a8a30aed5c91",
+       [
+        "bluetooth/device/watchAdvertisements/abort-signal-stops-events.https.window.html",
+        {
+         "script_metadata": [
+          [
+           "script",
+           "/resources/testdriver.js"
+          ],
+          [
+           "script",
+           "/resources/testdriver-vendor.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-test.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-fake-devices.js"
+          ]
+         ]
+        }
+       ]
+      ],
+      "abort-subsequent-watchAdvertisements-call-stops-events.https.window.js": [
+       "a5da75012bab1991a762c48f9a76f32906f2db11",
+       [
+        "bluetooth/device/watchAdvertisements/abort-subsequent-watchAdvertisements-call-stops-events.https.window.html",
+        {
+         "script_metadata": [
+          [
+           "script",
+           "/resources/testdriver.js"
+          ],
+          [
+           "script",
+           "/resources/testdriver-vendor.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-test.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-fake-devices.js"
+          ]
+         ]
+        }
+       ]
+      ],
+      "advertisementreceived-event-fired.https.window.js": [
+       "fff18bc47eed8434e3b4ff46cd157b5a5e41ea1a",
+       [
+        "bluetooth/device/watchAdvertisements/advertisementreceived-event-fired.https.window.html",
+        {
+         "script_metadata": [
+          [
+           "script",
+           "/resources/testdriver.js"
+          ],
+          [
+           "script",
+           "/resources/testdriver-vendor.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-test.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-fake-devices.js"
+          ]
+         ]
+        }
+       ]
+      ],
+      "concurrent-watchAdvertisements-calls.https.window.js": [
+       "cb6532be68ece2a04f5d70106f7b58869906b086",
+       [
+        "bluetooth/device/watchAdvertisements/concurrent-watchAdvertisements-calls.https.window.html",
+        {
+         "script_metadata": [
+          [
+           "script",
+           "/resources/testdriver.js"
+          ],
+          [
+           "script",
+           "/resources/testdriver-vendor.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-test.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-fake-devices.js"
+          ]
+         ]
+        }
+       ]
+      ],
+      "subsequent-watchAdvertisements-call.https.window.js": [
+       "797bfd1fa0b3ff4375d654895c21ca0d248982ad",
+       [
+        "bluetooth/device/watchAdvertisements/subsequent-watchAdvertisements-call.https.window.html",
+        {
+         "script_metadata": [
+          [
+           "script",
+           "/resources/testdriver.js"
+          ],
+          [
+           "script",
+           "/resources/testdriver-vendor.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-test.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-fake-devices.js"
+          ]
+         ]
+        }
+       ]
+      ],
+      "watching-two-devices-abort-one-watchAdvertisements.https.window.js": [
+       "8be02adb349a2010fea7e8f6424bdcb3d1788d93",
+       [
+        "bluetooth/device/watchAdvertisements/watching-two-devices-abort-one-watchAdvertisements.https.window.html",
+        {
+         "script_metadata": [
+          [
+           "script",
+           "/resources/testdriver.js"
+          ],
+          [
+           "script",
+           "/resources/testdriver-vendor.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-test.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-fake-devices.js"
+          ]
+         ]
+        }
+       ]
+      ],
+      "watching-two-devices.https.window.js": [
+       "32ec89a1eb0eaecf8b95f7c7b8026ad402438fd4",
+       [
+        "bluetooth/device/watchAdvertisements/watching-two-devices.https.window.html",
+        {
+         "script_metadata": [
+          [
+           "script",
+           "/resources/testdriver.js"
+          ],
+          [
+           "script",
+           "/resources/testdriver-vendor.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-test.js"
+          ],
+          [
+           "script",
+           "/bluetooth/resources/bluetooth-fake-devices.js"
+          ]
+         ]
+        }
+       ]
+      ]
      }
     },
     "getDevices": {
@@ -250299,7 +251110,7 @@
       ]
      ],
      "idl-BluetoothDevice.https.html": [
-      "ef2863dc27403a02bfa03cbb531b5e7c6c4b2ed4",
+      "8ba1c6387a88ce1d20b4915a15b74c3660e1ab5c",
       [
        null,
        {
@@ -254238,7 +255049,7 @@
     },
     "embedded-enforcement": {
      "allow_csp_from-header.html": [
-      "a806caf456ff894ec14000ab7e0ae9c2a15e3382",
+      "eda62dc5bcf66573da5f0930b4c76d0e6dff5bfe",
       [
        null,
        {}
@@ -254300,7 +255111,7 @@
       ]
      ],
      "subsumption_algorithm-general.html": [
-      "f8e6b0bd0f83f98a403676f4b2e1b04730941da2",
+      "28f7eaab0a0e6d943f136d370b58f6f38fa664b8",
       [
        null,
        {}
@@ -254342,7 +255153,7 @@
       ]
      ],
      "subsumption_algorithm-nonces.html": [
-      "4bd182e368c0d6e6821b7690683bef254ac5a224",
+      "33551be57d660fa3f5868ef1e875724b49da448d",
       [
        null,
        {}
@@ -254363,7 +255174,7 @@
       ]
      ],
      "subsumption_algorithm-strict_dynamic.html": [
-      "b3e0ea15bdc66e35bcea5ed09f3ad47571c8c45e",
+      "424e1bf9bab35f9a6ab264374e753e3f868c5b1e",
       [
        null,
        {}
@@ -269901,7 +270712,7 @@
     },
     "css-parser-api": {
      "idlharness.html": [
-      "078a1081ca48ce9ea17ceb3da6763ae19db14053",
+      "2c7fd39ce40ae4230e8bb8c7f8bfd7ceec967f91",
       [
        null,
        {}
@@ -270532,7 +271343,7 @@
       ]
      ],
      "at-property-cssom.html": [
-      "5a0ef9f5d005402da8bdd08a138d510cb45a3332",
+      "46671fedd4ec5d5682669f747b27d34d15ce6415",
       [
        null,
        {}
@@ -281592,7 +282403,7 @@
       ]
      ],
      "CSSStyleSheet-constructable.html": [
-      "e6293909c2178966a942abb7e544ff437e6d51d3",
+      "f84e4ea9af1657207b716ec9735676ac77977d4b",
       [
        null,
        {}
@@ -283692,13 +284503,6 @@
        null,
        {}
       ]
-     ],
-     "width-equals-window-inner-width.html": [
-      "775c1112de75e7703c28c2241b533e29e13ba5c5",
-      [
-       null,
-       {}
-      ]
      ]
     },
     "motion": {
@@ -301678,11 +302482,12 @@
      ]
     ],
     "mousedown.html": [
-     "e0f14f4c67db689e1868d8daf18ceafe943ab1f2",
+     "35a07faeb1bcaaadb0ca606f8948004b45a115ae",
      [
       null,
       {
-       "testdriver": true
+       "testdriver": true,
+       "timeout": "long"
       }
      ]
     ],
@@ -301741,11 +302546,12 @@
      ]
     ],
     "pointerdown.html": [
-     "3d7dcbe8cac2c72a98573275446dbe9d142cfc2d",
+     "2eb6ae898ccd006da1633a7f812dbcfc0fcbe9f1",
      [
       null,
       {
-       "testdriver": true
+       "testdriver": true,
+       "timeout": "long"
       }
      ]
     ],
@@ -302143,6 +302949,13 @@
       {}
      ]
     ],
+    "format-field-id-3.window.js": [
+     "3766fbf7bb1ea898c1f3b172ff9146142eda2592",
+     [
+      "eventsource/format-field-id-3.window.html",
+      {}
+     ]
+    ],
     "format-field-id-null.window.js": [
      "6d564dde0f211e57e6e766aa91ff66a13a5b1ddc",
      [
@@ -302364,50 +303177,6 @@
        {}
       ]
      ],
-     "lazyload": {
-      "lazyload-disabled-image-tentative.sub.html": [
-       "e5bb5d39f803854f9d2aa9a8973d4572ad37867f",
-       [
-        null,
-        {}
-       ]
-      ],
-      "lazyload-disabled-tentative.sub.html": [
-       "2ffcba71cea00faa56e47a48043ae10e4355479e",
-       [
-        null,
-        {}
-       ]
-      ],
-      "lazyload-enabled-image-tentative.sub.html": [
-       "8983762c31bdbd97233392b5f2a9ad2c97639f25",
-       [
-        null,
-        {}
-       ]
-      ],
-      "lazyload-enabled-tentative.sub.html": [
-       "d1171b5d06cf2a5122e0c57ea862de1083c23bcf",
-       [
-        null,
-        {}
-       ]
-      ],
-      "lazyload-image-loading-lazy-tentative.sub.html": [
-       "8f1ef1968eaa02db00e0733af89cbdc101b2a256",
-       [
-        null,
-        {}
-       ]
-      ],
-      "loading-frame-default-eager-disabled-tentative.sub.html": [
-       "fe249634f4e612c9e557cf5a170d9d4aa6ba1a09",
-       [
-        null,
-        {}
-       ]
-      ]
-     },
      "sync-script.tentative.https.sub.html": [
       "94f0dcf13fcf9453d8460bbd2102479974ac9c6e",
       [
@@ -310700,7 +311469,7 @@
       },
       "context-attributes": {
        "getContextAttributes.html": [
-        "fd1a4adb3a7766b96e8213e01cc7b92ab5e863a0",
+        "47b3d96233acf6b879959f48450be36beff99830",
         [
          null,
          {}
@@ -327247,6 +328016,44 @@
      ]
     },
     "cross-origin-opener-policy": {
+     "access-reporting": {
+      "openee-accessed_openee-coop-ro.https.html": [
+       "2f4ea87826df6ad2d78a13b6511a4aa530e7de57",
+       [
+        null,
+        {
+         "timeout": "long"
+        }
+       ]
+      ],
+      "openee-accessed_openee-coop.https.html": [
+       "07fd43b90ed93cfd40887d969cd79b08eeaa61ee",
+       [
+        null,
+        {
+         "timeout": "long"
+        }
+       ]
+      ],
+      "opener-accessed_openee-coop-ro.https.html": [
+       "c942b9c5d3b1c4bf678ffcc0c4d567a436422b63",
+       [
+        null,
+        {
+         "timeout": "long"
+        }
+       ]
+      ],
+      "opener-accessed_openee-coop.https.html": [
+       "921fdf742c2412578fd0ff0ac2cc7a43f3659754",
+       [
+        null,
+        {
+         "timeout": "long"
+        }
+       ]
+      ]
+     },
      "blob-popup.https.html": [
       "a26520d8d36c2e14ab3d11f4dec4aa6f3600e0f3",
       [
@@ -345258,7 +346065,7 @@
    },
    "input-device-capabilities": {
     "idlharness.window.js": [
-     "a57ae82993697695e4d05142c124ad36882becb1",
+     "fe4d01fb4a031d6bc77e64649bb6da7dd06f4a46",
      [
       "input-device-capabilities/idlharness.window.html",
       {
@@ -345270,8 +346077,13 @@
         [
          "script",
          "/resources/idlharness.js"
+        ],
+        [
+         "timeout",
+         "long"
         ]
-       ]
+       ],
+       "timeout": "long"
       }
      ]
     ]
@@ -346645,6 +347457,27 @@
         null,
         {}
        ]
+      ],
+      "mpadded-001.html": [
+       "edb2954d1478ae69320c048185767147e797d3b5",
+       [
+        null,
+        {}
+       ]
+      ],
+      "mpadded-002.html": [
+       "c3cbf7c435fd5b942b2c2528a9582c0b849d6e5d",
+       [
+        null,
+        {}
+       ]
+      ],
+      "mpadded-003.html": [
+       "4df55b993694b7661a613034dcddfc92712df970",
+       [
+        null,
+        {}
+       ]
       ]
      },
      "mrow": {
@@ -347400,6 +348233,13 @@
         {}
        ]
       ],
+      "dynamic-childlist-001.html": [
+       "8098c720fea39ab47ad08489aa5ebf7a32aa1930",
+       [
+        null,
+        {}
+       ]
+      ],
       "href-click-3.html": [
        "1b7f0685e65e7c939caab3d546316e7bf858f885",
        [
@@ -348288,7 +349128,7 @@
      ]
     ],
     "MediaStreamTrack-applyConstraints-getSettings.html": [
-     "a1695b1113028a3945f0c8aba8ab9a9cff4b502d",
+     "2ae3a87af2312a5c9045a378f5bf6d9113c21baa",
      [
       null,
       {
@@ -350547,7 +351387,7 @@
      ]
     ],
     "opaque-origin.https.window.js": [
-     "2385c31a786a223e5cdc23856edd41a55af783b2",
+     "265514760b691b4032123fd058dc2a9221f135b7",
      [
       "native-file-system/opaque-origin.https.window.html",
       {}
@@ -368055,6 +368895,29 @@
       {}
      ]
     ],
+    "css": {
+     "animation-timeline-computed.html": [
+      "02836d714b59081b3a14c2bd124d2ac254d23d58",
+      [
+       null,
+       {}
+      ]
+     ],
+     "animation-timeline-in-keyframe.html": [
+      "bdf40e0747ff96d58cabdfc820373434cd5e2fd8",
+      [
+       null,
+       {}
+      ]
+     ],
+     "animation-timeline-parsing.html": [
+      "8fac81e402f36123f0749b920e19e01c7586e12f",
+      [
+       null,
+       {}
+      ]
+     ]
+    },
     "current-time-nan.html": [
      "356f0a606826377aa20c6750cad7230fdc17c450",
      [
@@ -368150,6 +369013,15 @@
       {}
      ]
     ],
+    "scroll-animation-effect-phases.tentative.html": [
+     "df7ab69404cb00a9e09ec03593f531a50999630a",
+     [
+      null,
+      {
+       "timeout": "long"
+      }
+     ]
+    ],
     "scroll-animation-inactive-timeline.html": [
      "70b732eddd6fbcbd2accf9187c6394058e1a553f",
      [
@@ -369987,13 +370859,6 @@
        {}
       ]
      ],
-     "fetch-request-html-imports.https.html": [
-      "7a39fa85284addeb8b8d1144efda74bdfa0134fe",
-      [
-       null,
-       {}
-      ]
-     ],
      "fetch-request-no-freshness-headers.https.html": [
       "03b7d357610a904ed264b691054b6025f7fa2414",
       [
@@ -388021,7 +388886,7 @@
        ]
       ],
       "phases-and-states.html": [
-       "b62726c7e64b2733f7eb8c4e731e6bc8ad8df5bc",
+       "a33dbf517e893547160c42f3326a2e417a9709e3",
        [
         null,
         {}
@@ -388181,13 +389046,24 @@
     }
    },
    "web-bundle": {
-    "wbn-location.tentative.html": [
-     "e0604af6d1e19ac0661e518ba56574a587f3ffc5",
-     [
-      null,
-      {}
+    "subresource-loading": {
+     "link-web-bundle.tentative.html": [
+      "a4d1e70fc66d66b3ce0337a346582ef7d6fc082e",
+      [
+       null,
+       {}
+      ]
      ]
-    ]
+    },
+    "wbn-from-network": {
+     "wbn-location.tentative.html": [
+      "e0604af6d1e19ac0661e518ba56574a587f3ffc5",
+      [
+       null,
+       {}
+      ]
+     ]
+    }
    },
    "web-locks": {
     "acquire.tentative.https.any.js": [
@@ -390501,14 +391377,14 @@
        ]
       ],
       "convolver-response-1-chan.html": [
-       "dbd146d4db23c4d5810d4b3908987264feb8094e",
+       "300b43622bd96c51cd3a93c9627e31af9d1e2e5f",
        [
         null,
         {}
        ]
       ],
       "convolver-response-2-chan.html": [
-       "2d24236e661d070e13f275179ddd64de0671681d",
+       "9baf5f9f8d2c5ebda9c297647212eecb6fe9aa25",
        [
         null,
         {}
@@ -392481,7 +393357,7 @@
      ]
     ],
     "RTCPeerConnection-getStats.https.html": [
-     "2ecb21d2f19949fe198e587289430328d5345adf",
+     "bdf7770350e99fe6b730d3e91255f49f30961ed0",
      [
       null,
       {}
diff --git a/third_party/blink/web_tests/external/wpt/cors/resources/304.py b/third_party/blink/web_tests/external/wpt/cors/resources/304.py
index 2fc83b9..8fdf29a 100755
--- a/third_party/blink/web_tests/external/wpt/cors/resources/304.py
+++ b/third_party/blink/web_tests/external/wpt/cors/resources/304.py
@@ -1,62 +1,62 @@
 #!/usr/bin/env python
 
 # A header used to correlate requests and responses
-state_header = "content-language"
+state_header = b"content-language"
 
 # Static ETag to use (and expect)
-etag = "abcdef"
+etag = b"abcdef"
 
 def error(msg):
-    return (299, "Client Error"), [
-        ('content-type', 'text/plain'),
-        ('access-control-allow-origin', "*"),
-        ('access-control-expose-headers', state_header),
-        ('cache-control', 'no-store')
+    return (299, u"Client Error"), [
+        (b'content-type', b'text/plain'),
+        (b'access-control-allow-origin', b"*"),
+        (b'access-control-expose-headers', state_header),
+        (b'cache-control', b'no-store')
     ], msg
 
 def main(request, response):
     headers = []
 
-    inm = request.headers.get('if-none-match', None)
+    inm = request.headers.get(b'if-none-match', None)
     raw_req_num = request.headers.get(state_header, None)
     if raw_req_num == None:
-        return error("no req_num header in request")
+        return error(u"no req_num header in request")
     else:
         req_num = int(raw_req_num)
         if req_num > 8:
-            return error("req_num %s out of range" % req_num)
+            return error(u"req_num %s out of range" % req_num)
 
-    headers.append(("Access-Control-Expose-Headers", state_header))
+    headers.append((b"Access-Control-Expose-Headers", state_header))
     headers.append((state_header, req_num))
-    headers.append(("A", req_num))
-    headers.append(("B", req_num))
+    headers.append((b"A", req_num))
+    headers.append((b"B", req_num))
 
     if req_num % 2:  # odd requests are the first in a test pair
         if inm:
             # what are you doing here? This should be a fresh request.
-            return error("If-None-Match on first request")
+            return error(u"If-None-Match on first request")
         else:
-            status = 200, "OK"
-            headers.append(("Access-Control-Allow-Origin", "*"))
-            headers.append(("Content-Type", "text/plain"))
-            headers.append(("Cache-Control", "private, max-age=3, must-revalidate"))
-            headers.append(("ETag", etag))
-            return status, headers, "Success"
+            status = 200, u"OK"
+            headers.append((b"Access-Control-Allow-Origin", b"*"))
+            headers.append((b"Content-Type", b"text/plain"))
+            headers.append((b"Cache-Control", b"private, max-age=3, must-revalidate"))
+            headers.append((b"ETag", etag))
+            return status, headers, u"Success"
     else:  # even requests are the second in a pair, and should have a good INM.
         if inm != etag:
             # Bad browser.
             if inm == None:
-                return error("If-None-Match missing")
+                return error(u"If-None-Match missing")
             else:
-                return error("If-None-Match '%s' mismatches")
+                return error(u"If-None-Match '%s' mismatches")
         else:
             if req_num == 2:
                 pass  # basic, vanilla check
             elif req_num == 4:
-                headers.append(("Access-Control-Expose-Headers", "a, b"))
+                headers.append((b"Access-Control-Expose-Headers", b"a, b"))
             elif req_num == 6:
-                headers.append(("Access-Control-Expose-Headers", "a"))
+                headers.append((b"Access-Control-Expose-Headers", b"a"))
             elif req_num == 8:
-                headers.append(("Access-Control-Allow-Origin", "other.origin.example:80"))
-            status = 304, "Not Modified"
-            return status, headers, ""
+                headers.append((b"Access-Control-Allow-Origin", b"other.origin.example:80"))
+            status = 304, u"Not Modified"
+            return status, headers, u""
diff --git a/third_party/blink/web_tests/external/wpt/cors/resources/cache-304.py b/third_party/blink/web_tests/external/wpt/cors/resources/cache-304.py
index 7acdfd6..41cd16d9 100644
--- a/third_party/blink/web_tests/external/wpt/cors/resources/cache-304.py
+++ b/third_party/blink/web_tests/external/wpt/cors/resources/cache-304.py
@@ -1,10 +1,10 @@
 def main(request, response):
-    match = request.headers.get("If-None-Match", None)
-    if match is not None and match == "mybestscript-v1":
-        response.status = (304, "YEP")
-        return ""
-    response.headers.set("Access-Control-Allow-Origin", "*")
-    response.headers.set("Cache-Control", "must-revalidate")
-    response.headers.set("ETag", "mybestscript-v1")
-    response.headers.set("Content-Type", "text/javascript")
-    return "function hep() { }"
+    match = request.headers.get(b"If-None-Match", None)
+    if match is not None and match == b"mybestscript-v1":
+        response.status = (304, u"YEP")
+        return u""
+    response.headers.set(b"Access-Control-Allow-Origin", b"*")
+    response.headers.set(b"Cache-Control", b"must-revalidate")
+    response.headers.set(b"ETag", b"mybestscript-v1")
+    response.headers.set(b"Content-Type", b"text/javascript")
+    return u"function hep() { }"
diff --git a/third_party/blink/web_tests/external/wpt/cors/resources/checkandremove.py b/third_party/blink/web_tests/external/wpt/cors/resources/checkandremove.py
index f713d99..5cd7868 100644
--- a/third_party/blink/web_tests/external/wpt/cors/resources/checkandremove.py
+++ b/third_party/blink/web_tests/external/wpt/cors/resources/checkandremove.py
@@ -1,6 +1,6 @@
 def main(request, response):
-    token = request.GET.first("token")
+    token = request.GET.first(b"token")
     if request.server.stash.remove(token) is not None:
-        return "1"
+        return u"1"
     else:
-        return "0"
+        return u"0"
diff --git a/third_party/blink/web_tests/external/wpt/cors/resources/cors-cookie.py b/third_party/blink/web_tests/external/wpt/cors/resources/cors-cookie.py
index 061563e..ee42494a 100644
--- a/third_party/blink/web_tests/external/wpt/cors/resources/cors-cookie.py
+++ b/third_party/blink/web_tests/external/wpt/cors/resources/cors-cookie.py
@@ -1,21 +1,21 @@
 
 def main(request, response):
-    origin = request.GET.first("origin", request.headers["origin"])
-    credentials = request.GET.first("credentials", "true")
+    origin = request.GET.first(b"origin", request.headers[b"origin"])
+    credentials = request.GET.first(b"credentials", b"true")
 
-    headers = [("Content-Type", "text/plain")]
-    if origin != 'none':
-        headers.append(("Access-Control-Allow-Origin", origin))
-    if credentials != 'none':
-        headers.append(("Access-Control-Allow-Credentials", credentials))
+    headers = [(b"Content-Type", b"text/plain")]
+    if origin != b'none':
+        headers.append((b"Access-Control-Allow-Origin", origin))
+    if credentials != b'none':
+        headers.append((b"Access-Control-Allow-Credentials", credentials))
 
-    ident = request.GET.first('ident', 'test')
+    ident = request.GET.first(b'ident', b'test')
 
     if ident in request.cookies:
         body = request.cookies[ident].value
         response.delete_cookie(ident)
     else:
-        response.set_cookie(ident, "COOKIE")
-        body = "NO_COOKIE"
+        response.set_cookie(ident, b"COOKIE")
+        body = u"NO_COOKIE"
 
     return headers, body
diff --git a/third_party/blink/web_tests/external/wpt/cors/resources/cors-makeheader.py b/third_party/blink/web_tests/external/wpt/cors/resources/cors-makeheader.py
index eab35ee..8d6db74e 100644
--- a/third_party/blink/web_tests/external/wpt/cors/resources/cors-makeheader.py
+++ b/third_party/blink/web_tests/external/wpt/cors/resources/cors-makeheader.py
@@ -1,67 +1,69 @@
 import json
 
-def main(request, response):
-    origin = request.GET.first("origin", request.headers.get('origin'))
+from wptserve.utils import isomorphic_decode
 
-    if "check" in request.GET:
-        token = request.GET.first("token")
+def main(request, response):
+    origin = request.GET.first(b"origin", request.headers.get(b'origin'))
+
+    if b"check" in request.GET:
+        token = request.GET.first(b"token")
         value = request.server.stash.take(token)
         if value is not None:
-            if request.GET.first("check", None) == "keep":
+            if request.GET.first(b"check", None) == b"keep":
                 request.server.stash.put(token, value)
-            body = "1"
+            body = u"1"
         else:
-            body = "0"
-        return [("Content-Type", "text/plain")], body
+            body = u"0"
+        return [(b"Content-Type", b"text/plain")], body
 
 
-    if origin != 'none':
-        response.headers.set("Access-Control-Allow-Origin", origin)
-    if 'origin2' in request.GET:
-        response.headers.append("Access-Control-Allow-Origin", request.GET.first('origin2'))
+    if origin != b'none':
+        response.headers.set(b"Access-Control-Allow-Origin", origin)
+    if b'origin2' in request.GET:
+        response.headers.append(b"Access-Control-Allow-Origin", request.GET.first(b'origin2'))
 
     #Preflight
-    if 'headers' in request.GET:
-        response.headers.set("Access-Control-Allow-Headers", request.GET.first('headers'))
-    if 'credentials' in request.GET:
-        response.headers.set("Access-Control-Allow-Credentials", request.GET.first('credentials'))
-    if 'methods' in request.GET:
-        response.headers.set("Access-Control-Allow-Methods", request.GET.first('methods'))
+    if b'headers' in request.GET:
+        response.headers.set(b"Access-Control-Allow-Headers", request.GET.first(b'headers'))
+    if b'credentials' in request.GET:
+        response.headers.set(b"Access-Control-Allow-Credentials", request.GET.first(b'credentials'))
+    if b'methods' in request.GET:
+        response.headers.set(b"Access-Control-Allow-Methods", request.GET.first(b'methods'))
 
-    code_raw = request.GET.first('code', None)
+    code_raw = request.GET.first(b'code', None)
     if code_raw:
         code = int(code_raw)
     else:
         code = None
-    if request.method == 'OPTIONS':
+    if request.method == u'OPTIONS':
         #Override the response code if we're in a preflight and it's asked
-        if 'preflight' in request.GET:
-            code = int(request.GET.first('preflight'))
+        if b'preflight' in request.GET:
+            code = int(request.GET.first(b'preflight'))
 
         #Log that the preflight actually happened if we have an ident
-        if 'token' in request.GET:
-            request.server.stash.put(request.GET['token'], True)
+        if b'token' in request.GET:
+            request.server.stash.put(request.GET[b'token'], True)
 
-    if 'location' in request.GET:
+    if b'location' in request.GET:
         if code is None:
             code = 302
 
         if code >= 300 and code < 400:
-            response.headers.set("Location", request.GET.first('location'))
+            response.headers.set(b"Location", request.GET.first(b'location'))
 
     headers = {}
-    for name, values in request.headers.iteritems():
+    for name, values in request.headers.items():
         if len(values) == 1:
-            headers[name] = values[0]
+            headers[isomorphic_decode(name)] = isomorphic_decode(values[0])
         else:
             #I have no idea, really
             headers[name] = values
 
-    headers['get_value'] = request.GET.first('get_value', '')
+    headers[u'get_value'] = isomorphic_decode(request.GET.first(b'get_value', b''))
 
     body = json.dumps(headers)
 
     if code:
-        return (code, "StatusText"), [], body
+        return (code, u"StatusText"), [], body
     else:
         return body
diff --git a/third_party/blink/web_tests/external/wpt/cors/resources/expose-headers.py b/third_party/blink/web_tests/external/wpt/cors/resources/expose-headers.py
index c350b3b..e9de401 100644
--- a/third_party/blink/web_tests/external/wpt/cors/resources/expose-headers.py
+++ b/third_party/blink/web_tests/external/wpt/cors/resources/expose-headers.py
@@ -1,10 +1,10 @@
 def main(request, response):
     response.add_required_headers = False
-    output =  "HTTP/1.1 221 ALL YOUR BASE BELONG TO H1\r\n"
-    output += "Access-Control-Allow-Origin: *\r\n"
-    output += "BB-8: hey\r\n"
-    output += "Content-Language: mkay\r\n"
-    output += request.GET.first("expose") + "\r\n"
-    output += "\r\n"
+    output =  b"HTTP/1.1 221 ALL YOUR BASE BELONG TO H1\r\n"
+    output += b"Access-Control-Allow-Origin: *\r\n"
+    output += b"BB-8: hey\r\n"
+    output += b"Content-Language: mkay\r\n"
+    output += request.GET.first(b"expose") + b"\r\n"
+    output += b"\r\n"
     response.writer.write(output)
     response.close_connection = True
diff --git a/third_party/blink/web_tests/external/wpt/cors/resources/preflight.py b/third_party/blink/web_tests/external/wpt/cors/resources/preflight.py
index 978e97c5..d8bce26 100644
--- a/third_party/blink/web_tests/external/wpt/cors/resources/preflight.py
+++ b/third_party/blink/web_tests/external/wpt/cors/resources/preflight.py
@@ -1,35 +1,35 @@
 def main(request, response):
-    headers = [("Content-Type", "text/plain")]
+    headers = [(b"Content-Type", b"text/plain")]
 
-    if "check" in request.GET:
-        token = request.GET.first("token")
+    if b"check" in request.GET:
+        token = request.GET.first(b"token")
         value = request.server.stash.take(token)
         if value == None:
-            body = "0"
+            body = u"0"
         else:
-            if request.GET.first("check", None) == "keep":
+            if request.GET.first(b"check", None) == b"keep":
                 request.server.stash.put(token, value)
-            body = "1"
+            body = u"1"
 
         return headers, body
 
-    if request.method == "OPTIONS":
-        if not "Access-Control-Request-Method" in request.headers:
-            response.set_error(400, "No Access-Control-Request-Method header")
-            return "ERROR: No access-control-request-method in preflight!"
+    if request.method == u"OPTIONS":
+        if not b"Access-Control-Request-Method" in request.headers:
+            response.set_error(400, u"No Access-Control-Request-Method header")
+            return u"ERROR: No access-control-request-method in preflight!"
 
-        headers.append(("Access-Control-Allow-Methods",
-                        request.headers['Access-Control-Request-Method']))
+        headers.append((b"Access-Control-Allow-Methods",
+                        request.headers[b'Access-Control-Request-Method']))
 
-        if "max_age" in request.GET:
-            headers.append(("Access-Control-Max-Age", request.GET['max_age']))
+        if b"max_age" in request.GET:
+            headers.append((b"Access-Control-Max-Age", request.GET[b'max_age']))
 
-        if "token" in request.GET:
-            request.server.stash.put(request.GET.first("token"), 1)
+        if b"token" in request.GET:
+            request.server.stash.put(request.GET.first(b"token"), 1)
 
-    headers.append(("Access-Control-Allow-Origin", "*"))
-    headers.append(("Access-Control-Allow-Headers", "x-print"))
+    headers.append((b"Access-Control-Allow-Origin", b"*"))
+    headers.append((b"Access-Control-Allow-Headers", b"x-print"))
 
-    body = request.headers.get("x-print", "NO")
+    body = request.headers.get(b"x-print", b"NO")
 
     return headers, body
diff --git a/third_party/blink/web_tests/external/wpt/cors/resources/status.py b/third_party/blink/web_tests/external/wpt/cors/resources/status.py
index 96950dae..5d37e7a 100644
--- a/third_party/blink/web_tests/external/wpt/cors/resources/status.py
+++ b/third_party/blink/web_tests/external/wpt/cors/resources/status.py
@@ -1,37 +1,39 @@
+from wptserve.utils import isomorphic_encode
+
 def main(request, response):
-    response.headers.set("Access-Control-Allow-Origin", request.headers.get("origin"))
-    response.headers.set("Access-Control-Expose-Headers", "X-Request-Method")
+    response.headers.set(b"Access-Control-Allow-Origin", request.headers.get(b"origin"))
+    response.headers.set(b"Access-Control-Expose-Headers", b"X-Request-Method")
 
-    if request.method == 'OPTIONS':
-        response.headers.set("Access-Control-Allow-Methods",  "GET, CHICKEN, HEAD, POST, PUT")
+    if request.method == u'OPTIONS':
+        response.headers.set(b"Access-Control-Allow-Methods",  b"GET, CHICKEN, HEAD, POST, PUT")
 
-    if 'headers' in request.GET:
-        response.headers.set("Access-Control-Allow-Headers",  request.GET.first('headers'))
+    if b'headers' in request.GET:
+        response.headers.set(b"Access-Control-Allow-Headers",  request.GET.first(b'headers'))
 
-    response.headers.set("X-Request-Method", request.method)
+    response.headers.set(b"X-Request-Method", isomorphic_encode(request.method))
 
-    response.headers.set("X-A-C-Request-Method", request.headers.get("Access-Control-Request-Method", ""))
+    response.headers.set(b"X-A-C-Request-Method", request.headers.get(b"Access-Control-Request-Method", b""))
 
 
     #This should reasonably work for most response codes.
     try:
-        code = int(request.GET.first("code", 200))
+        code = int(request.GET.first(b"code", 200))
     except ValueError:
         code = 200
 
-    text = request.GET.first("text", "OMG")
+    text = request.GET.first(b"text", b"OMG")
 
-    if request.method == "OPTIONS" and "preflight" in request.GET:
+    if request.method == u"OPTIONS" and b"preflight" in request.GET:
         try:
-            code = int(request.GET.first('preflight'))
+            code = int(request.GET.first(b'preflight'))
         except KeyError:
             pass
 
     status = code, text
 
-    if "type" in request.GET:
-        response.headers.set("Content-Type", request.GET.first('type'))
+    if b"type" in request.GET:
+        response.headers.set(b"Content-Type", request.GET.first(b'type'))
 
-    body = request.GET.first('content', "")
+    body = request.GET.first(b'content', b"")
 
     return status, [], body
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-position/reference/subpixel-position-center-ref.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-position/reference/subpixel-position-center-ref.tentative.html
new file mode 100644
index 0000000..be20fbbe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-position/reference/subpixel-position-center-ref.tentative.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>CSS Backgrounds: Subpixel position center is centered, reference</title>
+  <link rel="author" title="Stephen Chenney" href="mailto:schenney@chromium.org">
+  <style>
+    .first{
+      outline: 2px solid green;
+      position: absolute;
+      width: 87.5px;
+      height: 87.5px;
+      left: 43.75px;
+      top: 43.75px;
+    }
+    .second {
+      background-image: url("../../resources/green-100.png");
+      background-repeat: no-repeat;
+      background-position: center center;
+      background-size: 38.5px 35px;
+      position: absolute;
+      width: 140px;
+      height: 140px;
+      left: 17.5px;
+      top: 17.5px;
+    }
+  </style>
+</head>
+<body>
+<div class="first"></div>
+<div class="second"></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-position/subpixel-position-center.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-position/subpixel-position-center.tentative.html
new file mode 100644
index 0000000..b708e12
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-position/subpixel-position-center.tentative.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>CSS Backgrounds: Subpixel position center is centered</title>
+  <link rel="author" title="Stephen Chenney" href="mailto:schenney@chromium.org">
+  <link rel="help" href="https://www.w3.org/TR/css-backgrounds-3/#background-position">
+  <link rel="match" href="reference/subpixel-position-center-ref.tentative.html">
+  <style>
+    .first{
+      outline: 2px solid green;
+      background-image: url("../../css-images/support/swatch-red.png");
+      background-repeat: no-repeat;
+      background-position: center center;
+      background-size: 38.5px 35px;
+      position: absolute;
+      width: 87.5px;
+      height: 87.5px;
+      left: 43.75px;
+      top: 43.75px;
+    }
+    .second {
+      background-image: url("../resources/green-100.png");
+      background-repeat: no-repeat;
+      background-position: center center;
+      background-size: 38.5px 35px;
+      position: absolute;
+      width: 140px;
+      height: 140px;
+      left: 17.5px;
+      top: 17.5px;
+    }
+  </style>
+</head>
+<body>
+<div class="first"></div>
+<div class="second"></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/table-with-float-paint.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/table-with-float-paint.html
new file mode 100644
index 0000000..da78a0a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/table-with-float-paint.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1090715">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<p>Test passes if there is a filled green square.</p>
+<div style="display: flex;">
+  <div style="display: table;">
+    <span style="float: left; width: 100px; height: 100px; background: green;"></span>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-parser-api/idlharness.html b/third_party/blink/web_tests/external/wpt/css/css-parser-api/idlharness.html
index 078a108..2c7fd39 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-parser-api/idlharness.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-parser-api/idlharness.html
@@ -1,6 +1,6 @@
 <!doctype html>
 <title>CSS Parser API IDL tests</title>
-<link rel="help" href="https://wicg.github.io/CSS-Parser-API/">
+<link rel="help" href="https://wicg.github.io/css-parser-api/">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/WebIDLParser.js"></script>
@@ -9,7 +9,7 @@
   'use strict';
 
   idl_test(
-    ['CSS-Parser-API'],
+    ['css-parser-api'],
     ['cssom'],
     idl_array => {
       // No objects
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/CSSStyleSheet-constructable.html b/third_party/blink/web_tests/external/wpt/css/cssom/CSSStyleSheet-constructable.html
index e629390..f84e4ea9 100644
--- a/third_party/blink/web_tests/external/wpt/css/cssom/CSSStyleSheet-constructable.html
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/CSSStyleSheet-constructable.html
@@ -590,7 +590,7 @@
   assert_throws_dom("SyntaxError", () => { (new CSSStyleSheet).insertRule(import_text) });
 }, 'Inserting an @import rule through insertRule on a constructed stylesheet throws an exception');
 
-async_test(t => {
+promise_test(t => {
     const importUrl = "support/constructable-import.css";
     const sheet = new CSSStyleSheet();
 
@@ -601,14 +601,17 @@
     link.rel = "stylesheet";
     link.href = importUrl;
 
-    link.addEventListener("error", t.unreached_func("Load shouldn't fail"));
-    link.addEventListener("load", t.step_func_done(event => {
-      let entries = window.performance.getEntriesByType('resource').filter(entry => entry.name.includes(importUrl));
-      assert_equals(entries.length, 1, "There should be only one entry for the import URL");
-      assert_greater_than_equal(entries[0].startTime, timeAfterReplaceSync, "The entry's start time should be after replaceSync threw");
-      link.remove();
-    }));
-    document.body.appendChild(link);
+    return new Promise(resolve => {
+      link.addEventListener("error", t.unreached_func("Load shouldn't fail"));
+      link.addEventListener("load", t.step_func(() => {
+        let entries = window.performance.getEntriesByType('resource').filter(entry => entry.name.includes(importUrl));
+        assert_equals(entries.length, 1, "There should be only one entry for the import URL");
+        assert_greater_than_equal(entries[0].startTime, timeAfterReplaceSync, "The entry's start time should be after replaceSync threw");
+        link.remove();
+        resolve();
+      }));
+      document.body.appendChild(link);
+    });
 }, "CSSStyleSheet.replaceSync should not trigger any loads from @import rules")
 
 promise_test(() => {
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/width-equals-window-inner-width.html b/third_party/blink/web_tests/external/wpt/css/mediaqueries/width-equals-window-inner-width.html
deleted file mode 100644
index 775c111..0000000
--- a/third_party/blink/web_tests/external/wpt/css/mediaqueries/width-equals-window-inner-width.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE html>
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>CSS Test: CSS media query width equals window innerWidth</title>
-
-<link rel="author" title="Jinfeng Ma" href="mailto:majinfeng1@xiaomi.org">
-<link rel="help" href="https://www.w3.org/TR/css3-mediaqueries/#width">
-<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-window-innerwidth">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<!--
-It'd be best to programmatically change device scale factor so that the document
-width becomes non integral but for now this test is only effective when run on
-devices with a fractional device scale factor.
--->
-<script type="text/javascript">
-    'use strict';
-    test(() => {
-      assert_true(window.matchMedia('(width: ' + window.innerWidth + 'px)').matches);
-    }, 'CSS media query width equals window innerWidth.');
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/docs/META.yml b/third_party/blink/web_tests/external/wpt/docs/META.yml
new file mode 100644
index 0000000..978b5c8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/META.yml
@@ -0,0 +1,2 @@
+suggested_reviewers:
+  - sideshowbarker
diff --git a/third_party/blink/web_tests/external/wpt/docs/Makefile b/third_party/blink/web_tests/external/wpt/docs/Makefile
new file mode 100644
index 0000000..1b7fe8e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/Makefile
@@ -0,0 +1,24 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    = -W -n
+SPHINXBUILD   = sphinx-build
+SOURCEDIR     = .
+BUILDDIR      = _build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+tools/%:
+	mkdir -p $(shell dirname $@)
+	test -d ../$@
+	ln -s ../../$@ $@
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile tools/wptserve tools/certs tools/wptrunner
+	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/third_party/blink/web_tests/external/wpt/docs/README.md b/third_party/blink/web_tests/external/wpt/docs/README.md
new file mode 100644
index 0000000..a753462
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/README.md
@@ -0,0 +1,24 @@
+# Project documentation tooling
+
+The documentation for the web-platform-tests project is built using [the Sphinx
+documentation generator](http://www.sphinx-doc.org). [The GitHub Actions
+service](https://github.com/features/actions) is configured to automatically
+update the public website each time changes are merged to the repository.
+
+## Local Development
+
+If you would like to build the site locally, follow these instructions.
+
+1. Install the system dependencies. The free and open source software tools
+   [Python](https://www.python.org/) and [Git](https://git-scm.com/) are
+   required. Each website has instructions for downloading and installing on a
+   variety of systems.
+2. Download the source code. Clone this repository using the `git clone`
+   command.
+3. Install the Python dependencies. Run the following command in a terminal
+   from the "docs" directory of the WPT repository:
+
+       pip install -r requirements.txt
+
+4. Build the documentation. Windows users should execute the `make.bat` batch
+   file. GNU/Linux and macOS users should use the `make` command.
diff --git a/third_party/blink/web_tests/external/wpt/docs/__init__.py b/third_party/blink/web_tests/external/wpt/docs/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/__init__.py
diff --git a/third_party/blink/web_tests/external/wpt/docs/admin/index.md b/third_party/blink/web_tests/external/wpt/docs/admin/index.md
new file mode 100644
index 0000000..98725bf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/admin/index.md
@@ -0,0 +1,94 @@
+# Project Administration
+
+This section documents all the information necessary to administer the
+infrastructure which makes the project possible.
+
+## Tooling
+
+```eval_rst
+.. toctree::
+   :titlesonly:
+
+   ../README
+   ../tools/wptserve/docs/index.rst
+   ../tools/wptrunner/README
+
+.. toctree::
+   :hidden:
+
+   ../tools/wptserve/README
+```
+
+## Secrets
+
+SSL certificates for all HTTPS-enabled domains are retrieved via [Let's
+Encrypt](https://letsencrypt.org/), so that data does not represent an
+explicitly-managed secret.
+
+## Third-party account owners
+
+- (unknown registrar): https://web-platform-tests.org
+  - jgraham@hoppipolla.co.uk
+- (unknown registrar): https://w3c-test.org
+  - mike@w3.org
+- (unknown registrar): http://testthewebforward.org
+  - web-human@w3.org
+- [Google Domains](https://domains.google/): https://wpt.fyi
+  - foolip@google.com
+  - robertma@google.com
+  - mike@bocoup.com
+- (Google internal): https://wpt.live https://wptpr.live
+  - foolip@google.com
+  - robertma@google.com
+- [GitHub](https://github.com/): web-platform-tests
+  - [@foolip](https://github.com/foolip)
+  - [@Hexcles](https://github.com/Hexcles)
+  - [@jgraham](https://github.com/jgraham)
+  - [@plehegar](https://github.com/plehegar)
+  - [@thejohnjansen](https://github.com/thejohnjansen)
+  - [@youennf](https://github.com/youennf)
+  - [@zcorpan](https://github.com/zcorpan)
+- [GitHub](https://github.com/): w3c
+  - [@plehegar](https://github.com/plehegar)
+  - [@sideshowbarker](https://github.com/sideshowbarker)
+- [Google Cloud Platform](https://cloud.google.com/): wptdashboard{-staging}
+  - robertma@google.com
+  - smcgruer@google.com
+  - foolip@google.com
+- [Google Cloud Platform](https://cloud.google.com/): wpt-live
+  - smcgruer@google.com
+  - robertma@google.com
+- [Google Cloud Platform](https://cloud.google.com/): wpt-pr-bot
+  - smcgruer@google.com
+  - robertma@google.com
+- E-mail address: wpt.pr.bot@gmail.com
+  - smcgruer@google.com
+  - boaz@bocoup.com
+  - mike@bocoup.com
+  - simon@bocoup.com
+- [GitHub](https://github.com/): @wpt-pr-bot account
+  - smcgruer@google.com
+  - boaz@bocoup.com
+  - mike@bocoup.com
+  - simon@bocoup.com
+
+[web-platform-tests]: https://github.com/e3c/web-platform-tests
+[wpt.fyi]: https://github.com/web-platform-tests/wpt.fyi
+
+## Emergency playbook
+
+### Lock down write access to the repo
+
+**Recommended but not yet verified approach:** Create a [new branch protection
+rule](https://github.com/web-platform-tests/wpt/settings/branch_protection_rules/new)
+that applies to `*` (i.e. all branches), and check "Restrict who can push to
+matching branches". This should prevent everyone except those with the
+"Maintain" role (currently only the GitHub admins listed above) from pushing
+to *any* branch. To lift the limit, delete this branch protection rule.
+
+**Alternative approach proven to work in
+[#21424](https://github.com/web-platform-tests/wpt/issues/21424):** Go to
+[manage access](https://github.com/web-platform-tests/wpt/settings/access),
+and change the permission of "reviewers" to "Read". To lift the limit, change
+it back to "Write". This has the known downside of *resubscribing all reviewers
+to repo notifications*.
diff --git a/third_party/blink/web_tests/external/wpt/docs/assets/commit-directly.png b/third_party/blink/web_tests/external/wpt/docs/assets/commit-directly.png
new file mode 100644
index 0000000..d02eef4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/assets/commit-directly.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/docs/assets/commitbtn.png b/third_party/blink/web_tests/external/wpt/docs/assets/commitbtn.png
new file mode 100644
index 0000000..2008489
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/assets/commitbtn.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/docs/assets/createpr.png b/third_party/blink/web_tests/external/wpt/docs/assets/createpr.png
new file mode 100644
index 0000000..4403a95
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/assets/createpr.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/docs/assets/custom.css b/third_party/blink/web_tests/external/wpt/docs/assets/custom.css
new file mode 100644
index 0000000..58a98257
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/assets/custom.css
@@ -0,0 +1,11 @@
+div.body {
+  min-width: auto;
+}
+
+#video-introduction-transcript iframe {
+  max-width: 100%;
+}
+
+.table-container {
+  overflow: auto;
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/docs/assets/files-changed.png b/third_party/blink/web_tests/external/wpt/docs/assets/files-changed.png
new file mode 100644
index 0000000..7472edc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/assets/files-changed.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/docs/assets/forkbtn.png b/third_party/blink/web_tests/external/wpt/docs/assets/forkbtn.png
new file mode 100644
index 0000000..f33cdd0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/assets/forkbtn.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/docs/assets/gh-fork-ribbon.scss b/third_party/blink/web_tests/external/wpt/docs/assets/gh-fork-ribbon.scss
new file mode 100644
index 0000000..c81530b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/assets/gh-fork-ribbon.scss
@@ -0,0 +1,124 @@
+/*!
+ * "Fork me on GitHub" CSS ribbon v0.2.2 | MIT License
+ * https://github.com/simonwhitaker/github-fork-ribbon-css
+*/
+
+.github-fork-ribbon {
+  width: 12.1em;
+  height: 12.1em;
+  position: absolute;
+  overflow: hidden;
+  top: 0;
+  right: 0;
+  z-index: 9999;
+  pointer-events: none;
+  font-size: 13px;
+  text-decoration: none;
+  text-indent: -999999px;
+}
+
+.github-fork-ribbon.fixed {
+  position: fixed;
+}
+
+.github-fork-ribbon:hover, .github-fork-ribbon:active {
+  background-color: rgba(0, 0, 0, 0.0);
+}
+
+.github-fork-ribbon:before, .github-fork-ribbon:after {
+  /* The right and left classes determine the side we attach our banner to */
+  position: absolute;
+  display: block;
+  width: 15.38em;
+  height: 1.54em;
+
+  top: 3.23em;
+  right: -3.23em;
+
+  -webkit-box-sizing: content-box;
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+
+  -webkit-transform: rotate(45deg);
+  -moz-transform: rotate(45deg);
+  -ms-transform: rotate(45deg);
+  -o-transform: rotate(45deg);
+  transform: rotate(45deg);
+}
+
+.github-fork-ribbon:before {
+  content: "";
+
+  /* Add a bit of padding to give some substance outside the "stitching" */
+  padding: .38em 0;
+
+  /* Set the base colour */
+  background-color: #a00;
+
+  /* Set a gradient: transparent black at the top to almost-transparent black at the bottom */
+  background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0.15)));
+  background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
+  background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
+  background-image: -ms-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
+  background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
+  background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
+
+  /* Add a drop shadow */
+  -webkit-box-shadow: 0 .15em .23em 0 rgba(0, 0, 0, 0.5);
+  -moz-box-shadow: 0 .15em .23em 0 rgba(0, 0, 0, 0.5);
+  box-shadow: 0 .15em .23em 0 rgba(0, 0, 0, 0.5);
+
+  pointer-events: auto;
+}
+
+.github-fork-ribbon:after {
+  /* Set the text from the data-ribbon attribute */
+  content: attr(data-ribbon);
+
+  /* Set the text properties */
+  color: #fff;
+  font: 700 1em "Helvetica Neue", Helvetica, Arial, sans-serif;
+  line-height: 1.54em;
+  text-decoration: none;
+  text-shadow: 0 -.08em rgba(0, 0, 0, 0.5);
+  text-align: center;
+  text-indent: 0;
+
+  /* Set the layout properties */
+  padding: .15em 0;
+  margin: .15em 0;
+
+  /* Add "stitching" effect */
+  border-width: .08em 0;
+  border-style: dotted;
+  border-color: #fff;
+  border-color: rgba(255, 255, 255, 0.7);
+}
+
+.github-fork-ribbon.left-top, .github-fork-ribbon.left-bottom {
+  right: auto;
+  left: 0;
+}
+
+.github-fork-ribbon.left-bottom, .github-fork-ribbon.right-bottom {
+  top: auto;
+  bottom: 0;
+}
+
+.github-fork-ribbon.left-top:before, .github-fork-ribbon.left-top:after, .github-fork-ribbon.left-bottom:before, .github-fork-ribbon.left-bottom:after {
+  right: auto;
+  left: -3.23em;
+}
+
+.github-fork-ribbon.left-bottom:before, .github-fork-ribbon.left-bottom:after, .github-fork-ribbon.right-bottom:before, .github-fork-ribbon.right-bottom:after {
+  top: auto;
+  bottom: 3.23em;
+}
+
+.github-fork-ribbon.left-top:before, .github-fork-ribbon.left-top:after, .github-fork-ribbon.right-bottom:before, .github-fork-ribbon.right-bottom:after {
+  -webkit-transform: rotate(-45deg);
+  -moz-transform: rotate(-45deg);
+  -ms-transform: rotate(-45deg);
+  -o-transform: rotate(-45deg);
+  transform: rotate(-45deg);
+}
diff --git a/third_party/blink/web_tests/external/wpt/docs/assets/more-commits.png b/third_party/blink/web_tests/external/wpt/docs/assets/more-commits.png
new file mode 100644
index 0000000..0d6b1a979
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/assets/more-commits.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/docs/assets/pencil-icon.png b/third_party/blink/web_tests/external/wpt/docs/assets/pencil-icon.png
new file mode 100644
index 0000000..ea347dd4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/assets/pencil-icon.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/docs/assets/praccepteddelete.png b/third_party/blink/web_tests/external/wpt/docs/assets/praccepteddelete.png
new file mode 100644
index 0000000..efb8e079
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/assets/praccepteddelete.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/docs/assets/pullrequestbtn.png b/third_party/blink/web_tests/external/wpt/docs/assets/pullrequestbtn.png
new file mode 100644
index 0000000..07d9c6a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/assets/pullrequestbtn.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/docs/assets/reftest-tutorial-test-screenshot.png b/third_party/blink/web_tests/external/wpt/docs/assets/reftest-tutorial-test-screenshot.png
new file mode 100644
index 0000000..8d88282
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/assets/reftest-tutorial-test-screenshot.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/docs/assets/testharness-tutorial-test-screenshot-1.png b/third_party/blink/web_tests/external/wpt/docs/assets/testharness-tutorial-test-screenshot-1.png
new file mode 100644
index 0000000..c469e94
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/assets/testharness-tutorial-test-screenshot-1.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/docs/assets/testharness-tutorial-test-screenshot-2.png b/third_party/blink/web_tests/external/wpt/docs/assets/testharness-tutorial-test-screenshot-2.png
new file mode 100644
index 0000000..612eda54
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/assets/testharness-tutorial-test-screenshot-2.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/docs/assets/web-platform.png b/third_party/blink/web_tests/external/wpt/docs/assets/web-platform.png
new file mode 100644
index 0000000..8547f491
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/assets/web-platform.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/docs/commands.json b/third_party/blink/web_tests/external/wpt/docs/commands.json
new file mode 100644
index 0000000..55408d8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/commands.json
@@ -0,0 +1,11 @@
+{
+  "build-docs": {
+    "path": "frontend.py",
+    "script": "build",
+    "help": "Build documentation",
+    "virtualenv": true,
+    "requirements": [
+      "./requirements.txt"
+    ]
+  }
+}
diff --git a/third_party/blink/web_tests/external/wpt/docs/conf.py b/third_party/blink/web_tests/external/wpt/docs/conf.py
new file mode 100644
index 0000000..89f30a02
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/conf.py
@@ -0,0 +1,199 @@
+# -*- coding: utf-8 -*-
+#
+# Configuration file for the Sphinx documentation builder.
+#
+# This file does only contain a selection of the most common options. For a
+# full list see the documentation:
+# http://www.sphinx-doc.org/en/master/config
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+import os
+import sys
+sys.path.insert(0, os.path.abspath('..'))
+sys.path.insert(0, os.path.abspath('../tools/wptserve'))
+sys.path.insert(0, os.path.abspath('../tools'))
+import localpaths
+
+# -- Project information -----------------------------------------------------
+
+project = u'web-platform-tests'
+copyright = u'2019, wpt contributors'
+author = u'wpt contributors'
+
+# The short X.Y version
+version = u''
+# The full version, including alpha/beta/rc tags
+release = u''
+
+
+# -- General configuration ---------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+    'recommonmark',
+    'sphinxarg.ext',
+    'sphinx.ext.autodoc',
+    'sphinx.ext.intersphinx'
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# These values are used in the documentation of wptserve but are not recognized
+# by Sphinx.
+# https://stackoverflow.com/questions/51824453/how-to-document-parameter-of-type-function-in-sphinx
+nitpick_ignore = [('py:class', 'Callable'), ('py:obj', 'None')]
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = [
+    '_build',
+    'Thumbs.db',
+    '.DS_Store'
+]
+
+from docs.wpt_lint_rules import WPTLintRules
+# Enable inline reStructured Text within Markdown-formatted files
+# https://recommonmark.readthedocs.io/en/latest/auto_structify.html
+from recommonmark.transform import AutoStructify
+def setup(app):
+    app.add_transform(AutoStructify)
+    app.add_directive('wpt-lint-rules', WPTLintRules)
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = None
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'alabaster'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#
+# html_theme_options = {}
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['assets']
+
+# Custom sidebar templates, must be a dictionary that maps document names
+# to template names.
+#
+# The default sidebars (for documents that don't match any pattern) are
+# defined by theme itself.  Builtin themes are using these templates by
+# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
+# 'searchbox.html']``.
+#
+# html_sidebars = {}
+
+
+# -- Options for HTMLHelp output ---------------------------------------------
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'web-platform-testsdoc'
+
+
+# -- Options for LaTeX output ------------------------------------------------
+
+latex_elements = {
+    # The paper size ('letterpaper' or 'a4paper').
+    #
+    # 'papersize': 'letterpaper',
+
+    # The font size ('10pt', '11pt' or '12pt').
+    #
+    # 'pointsize': '10pt',
+
+    # Additional stuff for the LaTeX preamble.
+    #
+    # 'preamble': '',
+
+    # Latex figure (float) alignment
+    #
+    # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+    (master_doc, 'web-platform-tests.tex', u'web-platform-tests Documentation',
+     u'wpt contributors', 'manual'),
+]
+
+
+# -- Options for manual page output ------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    (master_doc, 'web-platform-tests', u'web-platform-tests Documentation',
+     [author], 1)
+]
+
+
+# -- Options for Texinfo output ----------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+    (master_doc, 'web-platform-tests', u'web-platform-tests Documentation',
+     author, 'web-platform-tests', 'One line description of project.',
+     'Miscellaneous'),
+]
+
+
+# -- Options for Epub output -------------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = project
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+#
+# epub_identifier = ''
+
+# A unique identification for the text.
+#
+# epub_uid = ''
+
+# A list of files that should not be packed into the epub file.
+epub_exclude_files = ['search.html']
+
+intersphinx_mapping = {'python': ('https://docs.python.org/2/', None),
+                       'mozilla': ('https://firefox-source-docs.mozilla.org/', None)}
diff --git a/third_party/blink/web_tests/external/wpt/docs/frontend.py b/third_party/blink/web_tests/external/wpt/docs/frontend.py
new file mode 100644
index 0000000..4b97e2e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/frontend.py
@@ -0,0 +1,8 @@
+import subprocess
+import os
+
+here = os.path.dirname(__file__)
+
+
+def build(*args, **kwargs):
+    subprocess.check_call(["make", "html"], cwd=here)
diff --git a/third_party/blink/web_tests/external/wpt/docs/index.md b/third_party/blink/web_tests/external/wpt/docs/index.md
new file mode 100644
index 0000000..419c99a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/index.md
@@ -0,0 +1,81 @@
+# web-platform-tests documentation
+
+The web-platform-tests project is a cross-browser test suite for [the
+Web-platform stack](https://platform.html5.org). Writing tests in a way that
+allows them to be run in all browsers gives browser projects confidence that
+they are shipping software which is compatible with other implementations, and
+that later implementations will be compatible with their implementations. This
+in turn gives Web authors/developers confidence that they can actually rely on
+the Web platform to deliver on the promise of working across browsers and
+devices without needing extra layers of abstraction to paper over the gaps left
+by specification editors and implementors.
+
+
+The most important sources of information and activity are:
+
+- [github.com/web-platform-tests/wpt](https://github.com/web-platform-tests/wpt):
+  the canonical location of the project's source code revision history and the
+  discussion forum for changes to the code
+- [web-platform-tests.org](https://web-platform-tests.org): the documentation
+  website; details how to set up the project, how to write tests, how to give
+  and receive peer review, how to serve as an administrator, and more
+- [wpt.live](http://wpt.live): a public deployment of the test suite,
+  allowing anyone to run the tests by visiting from an
+  Internet-enabled browser of their choice
+- [wpt.fyi](https://wpt.fyi): an archive of test results collected from an
+  array of web browsers on a regular basis
+- [Real-time chat room](http://irc.w3.org/?channels=testing): the
+  [IRC](http://www.irchelp.org/) chat room named `#testing` on
+  [irc.w3.org](https://www.w3.org/wiki/IRC); includes participants located
+  around the world, but busiest during the European working day; [all
+  discussion is archived here](https://w3.logbot.info/testing)
+- [Mailing list](https://lists.w3.org/Archives/Public/public-test-infra/): a
+  public and low-traffic discussion list
+
+**If you'd like clarification about anything**, don't hesitate to ask in the
+chat room or on the mailing list.
+
+## Video Introduction ([transcript](intro-video-transcript))
+
+<iframe
+  width="560"
+  height="315"
+  src="https://www.youtube.com/embed/zuK1uyXPZS0"
+  frameborder="0"
+  allow="autoplay; encrypted-media"
+  allowfullscreen></iframe>
+
+See also [this lecture from Web Engines Hackfest 2018 (30
+minutes)](https://www.youtube.com/watch?v=XnfE3MfH5hQ)
+
+## GitHub
+
+[GitHub](https://github.com/web-platform-tests/wpt/) is used both for [issue tracking](https://github.com/web-platform-tests/wpt/issues) and [test submissions](https://github.com/web-platform-tests/wpt/pulls); we
+provide [a limited introduction][github-intro] to both git and
+GitHub.
+
+Pull Requests are automatically labeled based on the directory the
+files they change are in; there are also comments added automatically
+to notify a number of people: this list of people comes from META.yml
+files in those same directories and their parents (i.e., they work
+recursively: `a/META.yml` will get notified for `a/foo.html` and
+`a/b/bar.html`).
+
+If you want to be notified about changes to tests in a directory, feel
+free to add yourself to the META.yml file!
+
+## Table of Contents
+
+```eval_rst
+.. toctree::
+   :maxdepth: 2
+
+   test-suite-design
+   intro-video-transcript
+   running-tests/index
+   writing-tests/index
+   reviewing-tests/index
+   admin/index
+```
+
+[github-intro]: writing-tests/github-intro
diff --git a/third_party/blink/web_tests/external/wpt/docs/intro-video-transcript.md b/third_party/blink/web_tests/external/wpt/docs/intro-video-transcript.md
new file mode 100644
index 0000000..b43ebf72
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/intro-video-transcript.md
@@ -0,0 +1,232 @@
+# "Introduction to WPT" video transcript
+
+<iframe
+  width="560"
+  height="315"
+  src="https://www.youtube.com/embed/zuK1uyXPZS0"
+  frameborder="0"
+  allow="autoplay; encrypted-media"
+  allowfullscreen></iframe>
+
+**Still image of the WPT logo. The song ["My
+Luck"](http://brokeforfree.bandcamp.com/track/my-luck) by [Broke for
+Free](http://brokeforfree.com/) (licensed under [Creative Commons Attribution
+3.0](https://creativecommons.org/licenses/by/3.0/))
+plays in the background.**
+
+> Hello, and welcome to the Web Platform Tests!
+>
+> The goal of this project is to ensure that all web browsers present websites
+> in exactly the way the authors intended.
+>
+> But what is the web platform, exactly? You can think of it as having three
+> main parts.
+
+**A top-down shot of a blank sheet of graph paper**
+
+> First, there are the web browsers.
+
+A hand places a paper cutout depicting a browser window in the lower-right
+corner of the sheet.
+
+> Applications like Firefox, Chrome, and Safari allow people to interact with
+> pages and with each other.
+>
+> Second, there are the web standards.
+
+A hand places a paper cutout depicting a scroll of parchment paper in the
+lower-left corner of the sheet.
+
+> These documents define how the browsers are supposed to behave.
+
+**A screen recording of a web browser**
+
+`https://platform.html5.org` is entered into the location bar, and the browser
+loads the page.
+
+> That includes everything from how text is rendered to how augmented reality
+> apps are built. Specifying it all takes a lot of work!
+
+The browser clicks through to the Fetch standard and begins scrolling.
+
+> And as you might expect, the standards can get really complicated.
+
+**Return to the graph paper**
+
+A hand draws an arrow from the cutout of the scroll to the cutout of the
+browser window.
+
+> The people who build the browsers use the specifications as a blue print for
+> their work. A shared set of generic instructions like these make it possible
+> for people to choose between different browsers, but only if the browsers get
+> it right.
+
+A hand places a cutout representing a stack of papers on the top-center of the
+sheet and draws an arrow from that cutout to the cutout of the browser window.
+
+> To verify their work, the browser maintainers rely on the third part of the
+> web platform: conformance tests.
+
+A hand draws an arrow from the cutout of the scroll to the cutout of the tests.
+
+> We author tests to describe the same behavior as the standards, just
+> formatted in a way that a computer can understand.
+
+A hand draws an arrow from the cutout of the browser window to the cutout of
+the scroll.
+
+> In the process, the maintainers sometimes uncover problems in the design of
+> the specifications, and they recommend changes to fix them.
+
+A hand draws an arrow from the cutout of the tests to the cutout of the scroll.
+
+> Test authors also find and fix these so-called "spec bugs."
+
+A hand draws an arrow from the cutout of the browser window to the cutout of
+the tests.
+
+> ...and as they implement the standards, the maintainers of each browser
+> frequently write new tests that can be shared with the others.
+>
+> This is how thousands of people coordinate to build the cohesive programming
+> platform that we call the world wide web. The web-platform-tests project is
+> one of the test suites that make this possible.
+>
+> That's pretty abstract, though! Let's take a quick look at the tests
+> themselves.
+
+**A screen recording of a web browser**
+
+`http://wpt.live` is entered into the location bar, and the browser loads the
+page.
+
+> The latest version of the tests is publicly hosted in executable form on the
+> web at wpt.live.
+
+The browser begins scrolling through the enormous list of directories.
+
+> There, were can navigate among all the tests for all the different web
+> technologies.
+>
+> Let's take a look at a typical test.
+
+The browser stops scrolling, and a mouse cursor clicks on `fetch`, then `api`,
+then `headers`, and finally `headers-basic.html`.
+
+> This test is written with the web-platform-tests's testing framework,
+> testharness.js. The test completes almost instantly, and testharness.js
+> reports that this browser passes all but one subtest. To understand the
+> failure, we can read the source code.
+
+The mouse opens a context menu, selects "View Source", and scrolls to the
+source of the failing test.
+
+> It looks like the failing subtest is for what happens when a `Headers`
+> instance has a custom JavaScript iterator method. That's a strange edge case,
+> but it's important for browsers to agree on every detail!
+
+The mouse clicks on the browser's "Back" button and then navigates through the
+directory structure to the test at
+`css/css-transforms/transform-transformed-tr-contains-fixed-position.html`. It
+displays text rendered at an angle.
+
+> Many tests don't use testharness.js at all. Let's take a look at a couple
+> other test types.
+>
+> When it comes to the visual appearance of a page, it can be hard to verify
+> the intended behavior using JavaScript alone. For these situations, the
+> web-platform-tests uses what's known as a reftest.
+>
+> Short for "reference test", this type of test uses at least two different web
+> pages.
+>
+> The first page demonstrates the feature under test.
+
+The mouse opens a context menu, selects "View Source", and clicks on the `href`
+value for the matching reference. It looks identical to the previous page.
+
+> Inside of it, we'll find a link to a second page. This second page is the
+> reference page. It's designed to use a different approach to produce the same
+> output.
+
+The mouse clicks back and forth between the browser tabs displaying the test
+page and the reference page.
+
+> When tests like these are run automatically, a computer verifies that
+> screenshots of the two pages are identical.
+
+The mouse clicks on the browser's "Back" button and then navigates through the
+directory structure to the test at
+`css/css-animations/animation-fill-mode-002-manual.html`. The page includes the
+text, "Test passes if there is a filled color square with 'Filler Text', whose
+color gradually changes in the order: YELLOW to GREEN." It also includes the
+described animated square.
+
+> Even with testharness.js and reftests, there are many web platform features
+> that a computer can't automatically verify. In cases like these, we fall back
+> to using manual tests.
+>
+> Manual tests can only be verified by a living, breathing human. They describe
+> their expectations in plain English so that a human operator can easily
+> determine whether the browser is behaving correctly.
+
+`https://web-platform-tests.org` is entered into the location bar, and the
+browser loads the page.
+
+> You can read more about all the test types in the project documentation at
+> [web-platform-tests.org](https://web-platform-tests.org).
+
+`https://wpt.fyi` is entered into the location bar, and the browser loads the
+page.
+
+> [wpt.fyi](https://wpt.fyi) is a great way to see how today's browsers are
+> performing on the web-platform-tests.
+
+The browser scrolls to `fetch`, and a mouse cursor clicks on `fetch`, then
+`api`, then `headers`, and finally `headers-basic.html`.
+
+> Here, you'll find all the same tests, just presented with the results from
+> various browsers.
+
+`https://web-platform-tests.live/LICENSE.md` is entered into the location bar,
+and the browser loads the page.
+
+> The web-platform-tests project is free and open source software. From bug
+> reports to documentation improvements and brand new tests, we welcome all
+> sorts of contributions from everyone.
+
+`https://github.com/web-platform-tests/wpt` is entered into the location bar,
+and the browser loads the page.
+
+> To get involved, you can visit the project management website hosted on
+> GitHub.com.
+
+The browser navigates to the project's "issues" list and filters the list for
+just the ones labeled as "good first issue."
+
+> Some issues are more difficult than others, but many are perfect for people who
+> are just getting started with the project. When we come across an issue like
+> that, we label it as a "good first issue."
+
+`https://lists.w3.org/Archives/Public/public-test-infra` is entered into the
+location bar, and the browser loads the page.
+
+> You can also join the mailing list to receive e-mail with announcements and
+> discussion about the project.
+
+`http://irc.w3.org/` is entered into the location bar, and the browser loads
+the page. `web4all` is entered as the Nickname, and `#testing` is entered as
+the channel name. A mouse clicks on the "Connect" button.
+
+> For more immediate communication, you can join the "testing" channel on the
+> IRC server run by the W3C.
+
+**Return to the graph paper**
+
+A hand places a paper cutout depicting a human silhouette on the sheet. It then
+draws arrows from the new cutout to each of the three previously-introduced
+cutouts.
+
+![](assets/web-platform.png "The diagram drawn in the video")
+
+> We're looking forward to working with you!
diff --git a/third_party/blink/web_tests/external/wpt/docs/make.bat b/third_party/blink/web_tests/external/wpt/docs/make.bat
new file mode 100755
index 0000000..49607bb0a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/make.bat
@@ -0,0 +1,41 @@
+@ECHO OFF

+

+pushd %~dp0

+

+REM Command file for Sphinx documentation

+

+if "%SPHINXBUILD%" == "" (

+	set SPHINXBUILD=sphinx-build

+)

+set SOURCEDIR=.

+set BUILDDIR=_build

+

+if "%1" == "" goto help

+

+%SPHINXBUILD% >NUL 2>NUL

+if errorlevel 9009 (

+	echo.

+	echo.The 'sphinx-build' command was not found. Make sure you have Sphinx

+	echo.installed, then set the SPHINXBUILD environment variable to point

+	echo.to the full path of the 'sphinx-build' executable. Alternatively you

+	echo.may add the Sphinx directory to PATH.

+	echo.

+	echo.If you don't have Sphinx installed, grab it from

+	echo.http://sphinx-doc.org/

+	exit /b 1

+)

+

+if not exist tools\ ( mkdir tools )

+

+if not exist tools\wptserve\ ( mklink /d tools\wptserve ..\..\tools\wptserve )

+if not exist tools\certs\ ( mklink /d tools\certs ..\..\tools\certs )

+if not exist tools\wptrunner\ ( mklink /d tools\wptrunner ..\..\tools\wptrunner )

+

+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%

+goto end

+

+:help

+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%

+

+:end

+popd

diff --git a/third_party/blink/web_tests/external/wpt/docs/requirements.txt b/third_party/blink/web_tests/external/wpt/docs/requirements.txt
new file mode 100644
index 0000000..a9ddeecf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/requirements.txt
@@ -0,0 +1,4 @@
+recommonmark==0.6.0
+# pin this to the last Py2 release
+Sphinx==1.8.5  # pyup: <2.0
+sphinx-argparse==0.2.5
diff --git a/third_party/blink/web_tests/external/wpt/docs/reviewing-tests/checklist.md b/third_party/blink/web_tests/external/wpt/docs/reviewing-tests/checklist.md
new file mode 100644
index 0000000..0e50843f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/reviewing-tests/checklist.md
@@ -0,0 +1,157 @@
+# Review Checklist
+
+The following checklist is provided as a guideline to assist in reviewing
+tests; in case of any contradiction with requirements stated elsewhere in the
+documentation it should be ignored
+(please [file a bug](https://github.com/web-platform-tests/wpt/issues/new)!).
+
+As noted on the [reviewing tests](index) page, nits need not block PRs
+from landing.
+
+
+## All tests
+
+<label><input type="checkbox">
+The CI jobs on the pull request have passed.
+</label>
+
+<label><input type="checkbox">
+It is obvious what the test is trying to test.
+</label>
+
+<label><input type="checkbox">
+The test passes when it's supposed to pass.
+</label>
+
+<label><input type="checkbox">
+The test fails when it's supposed to fail.
+</label>
+
+<label><input type="checkbox">
+The test is testing what it thinks it's testing.
+</label>
+
+<label><input type="checkbox">
+The spec backs up the expected behavior in the test.
+</label>
+
+<label><input type="checkbox">
+The test is automated as either [reftest](../writing-tests/reftests) or
+a [script test](../writing-tests/testharness) unless there's a very good reason for it not to be.
+</label>
+
+<label><input type="checkbox">
+The test does not use external resources.
+</label>
+
+<label><input type="checkbox">
+The test does not use proprietary features (vendor-prefixed or otherwise).
+</label>
+
+<label><input type="checkbox">
+The test does not contain commented-out code.
+</label>
+
+<label><input type="checkbox">
+The test is placed in the relevant directory.
+</label>
+
+<label><input type="checkbox">
+The test has a reasonable and concise filename.
+</label>
+
+<label><input type="checkbox">
+If the test needs code running on the server side, the server code must be
+written in Python, and the Python code must not do anything potentially unsafe.
+</label>
+
+<label><input type="checkbox">
+If the test needs to be run in some non-standard configuration or needs user
+interaction, it is a manual test.
+</label>
+
+<label><input type="checkbox">
+**Nit**: The title is descriptive but not too wordy.
+</label>
+
+
+## Reftests Only
+
+<label><input type="checkbox">
+The reference file is accurate and will render pixel-perfect
+identically to the test on all platforms.
+</label>
+
+<label><input type="checkbox">
+The reference file uses a different technique that won't fail in
+the same way as the test.
+</label>
+
+<label><input type="checkbox">
+The test and reference render within a 800x600 viewport, only displaying
+scrollbars if their presence is being tested.
+</label>
+
+<label><input type="checkbox">
+**Nit**: The test has a self-describing statement.
+</label>
+
+<label><input type="checkbox">
+**Nit**: The self-describing statement is accurate, precise, simple, and
+self-explanatory. Someone with no technical knowledge should be able to say
+whether the test passed or failed within a few seconds, and not need to spend
+several minutes thinking or asking questions.
+</label>
+
+
+## Script Tests Only
+
+<label><input type="checkbox">
+The number of tests in each file and the test names are consistent
+across runs and browsers. It is best to avoid the pattern where there is
+a test that asserts that the feature is supported and bails out without
+running the rest of the tests in the file if it isn't.
+</label>
+
+<label><input type="checkbox">
+The test avoids patterns that make it less likely to be stable.
+In particular, tests should avoid setting internal timeouts, since the
+time taken to run it may vary on different devices; events should be used
+instead (if at all possible).
+</label>
+
+<label><input type="checkbox">
+The test uses the most specific asserts possible (e.g. doesn't use
+`assert_true` for everything).
+</label>
+
+<label><input type="checkbox">
+The test uses `idlharness.js` if it is testing basic IDL-defined behavior.
+</label>
+
+<label><input type="checkbox">
+**Nit**: Tests in a single file are separated by one empty line.
+</label>
+
+
+## Visual Tests Only
+
+<label><input type="checkbox">
+The test has a self-describing statement.
+</label>
+
+<label><input type="checkbox">
+The self-describing statement is accurate, precise, simple, and
+self-explanatory. Someone with no technical knowledge should be able to say
+whether the test passed or failed within a few seconds, and not need to spend
+several minutes thinking or asking questions.
+</label>
+
+<label><input type="checkbox">
+The test renders within a 800x600 viewport, only displaying scrollbars if their
+presence is being tested.
+</label>
+
+<label><input type="checkbox">
+The test renders to a fixed, static page with no animation.
+</label>
diff --git a/third_party/blink/web_tests/external/wpt/docs/reviewing-tests/email.md b/third_party/blink/web_tests/external/wpt/docs/reviewing-tests/email.md
new file mode 100644
index 0000000..55bbf44
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/reviewing-tests/email.md
@@ -0,0 +1,7 @@
+# Email Filters
+
+See the [GitHub support page](https://help.github.com/articles/about-email-notifications/)
+for how to filter certain types of email notifications. These are the most
+useful `Cc` addresses when reviewing in web-platform-tests:
+- `review_requested@noreply.github.com` when you are added as a (suggested) `reviewer` on a pull request.
+- `assign@noreply.github.com` when you are added as the `assignee` (i.e. as _the_ reviewer) on a pull request.
diff --git a/third_party/blink/web_tests/external/wpt/docs/reviewing-tests/git.md b/third_party/blink/web_tests/external/wpt/docs/reviewing-tests/git.md
new file mode 100644
index 0000000..b74b4b7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/reviewing-tests/git.md
@@ -0,0 +1,83 @@
+# Working with Pull Requests as a reviewer
+
+In order to do a thorough review,
+it is sometimes desirable to have a local copy of the tests one wishes to review.
+
+Reviewing tests also often results in wanting a few things to be changed.
+Generally, the reviewer should ask the author to make the desired changes.
+However, sometimes the original author does not respond to the requests,
+or the changes are so trivial (e.g. fixing a typo)
+that bothering the original author seems like a waste of time.
+
+Here is how to do all that.
+
+## Trivial cases
+
+If it is possible to review the tests without a local copy,
+but the reviewer still wants to make some simple tweaks to the tests before merging,
+it is possible to do so via the Github web UI.
+
+1. Open the pull request. E.g. https://github.com/web-platform-tests/wpt/pull/1234
+2. Go to the ![Files changed](../assets/files-changed.png) view (e.g. https://github.com/web-platform-tests/wpt/pull/1234/files)
+3. Locate the files you wish to change, and click the ![pencil](../assets/pencil-icon.png) icon in the upper right corner
+4. Make the desired change
+5. Write a commit message (including a good title) at the bottom
+6. Make sure the ![Commit directly to the [name-of-the-PR-branch] branch.](../assets/commit-directly.png) radio button is selected.
+
+   _Note: If the PR predates the introduction of this feature by Github,
+   or if the author of the PR has disabled write-access by reviewers to the PR branch,
+   this may not be available,
+   and your only option would be to commit to a new branch, creating a new PR._
+7. Click the ![Commit Changes](../assets/commitbtn.png) button.
+
+
+## The Normal Way
+
+This is how to import the Pull Request's branch into your existing local
+checkout of the repository. If you don't have one, go [fork][fork],
+[clone][clone], and [configure][configure] it.
+
+1. Move into your local clone: `cd wherever-you-put-your-repo`
+2. Add a remote for the PR author's repo: `git remote add <author-id> git://github.com/<author-id>/<repo-name>.git`
+3. Fetch the PR: `git fetch <author-id> <name-of-the-PR-branch>`
+4. Checkout that branch: `git checkout <name-of-the-PR-branch>`
+
+   _The relevant `<author-id>`, `<repo-name>`, and `<name-of-the-PR-branch>` can be found by looking for this sentence in on the Github page of the PR:
+   ![Add more commits by pushing to the name-of-the-PR-branch branch on author-id/repo-name.](../assets/more-commits.png)_
+
+If all you meant to do was reviewing files locally, you're all set.
+If you wish to make changes to the PR branch:
+
+1. Make changes and [commit][commit] normally
+2. Push your changes upstream: `git push <author-id> <name-of-the-PR-branch>`
+
+   _Note: If the PR predates the introduction of this feature by Github,
+   or if the author of the PR has disabled write-access by reviewers to the PR branch,
+   this will not work, and you will need to use the alternative described below._
+
+If, instead of modifying the existing PR, you wish to make a new one based on it:
+
+1. Set up a new branch that contains the existing PR by doing one of the following:
+   1. Create a new branch from the tip of the PR:
+   `git branch <your-new-branch> <name-of-the-PR-branch> && git checkout <your-new-branch>`
+   2. Create a new branch from `master` and merge the PR into it:
+   `git branch <your-new-branch> master && git checkout <your-new-branch> && git merge <name-of-the-PR-branch>`
+2. Make changes and [commit][commit] normally
+3. Push your changes to **your** repo: `git push origin <your-new-branch>`
+4. Go to the Github Web UI to [submit a new Pull Request][submit].
+
+   _Note: You should also close the original pull request._
+
+When you're done reviewing or making changes,
+you can delete the branch: `git branch -d <name-of-the-PR-branch>`
+(use `-D` instead of `-d` to delete a branch that has not been merged into master yet).
+
+If you do not expect work with more PRs from the same author,
+you may also discard your connection to their repo:
+`git remote remove <author-id>`
+
+[clone]: ../writing-tests/github-intro.html#clone
+[commit]: ../writing-tests/github-intro.html#commit
+[configure]: ../writing-tests/github-intro.html#configure-remote-upstream
+[fork]: ../writing-tests/github-intro.html#fork-the-test-repository
+[submit]: ../writing-tests/github-intro.html#submit
diff --git a/third_party/blink/web_tests/external/wpt/docs/reviewing-tests/index.md b/third_party/blink/web_tests/external/wpt/docs/reviewing-tests/index.md
new file mode 100644
index 0000000..e313f84
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/reviewing-tests/index.md
@@ -0,0 +1,62 @@
+# Reviewing Tests
+
+In order to encourage a high level of quality in the W3C test
+suites, test contributions must be reviewed by a peer.
+
+```eval_rst
+.. toctree::
+   :maxdepth: 1
+
+   checklist
+   email
+   git
+   reverting
+```
+
+## Test Review Policy
+
+The reviewer can be anyone (other than the original test author) that
+has the required experience with both the spec under test and with
+the [general test guidelines](../writing-tests/general-guidelines).
+
+The review must happen in public, but there is no requirement for it
+to happen in any specific location. In particular if a vendor is
+submitting tests that have already been publicly reviewed in their own
+review system, that review may be carried forward. For other submissions, we
+recommend using GitHub's built-in review tools.
+
+Regardless of what review tool is used, the review must be clearly
+linked in the pull request.
+
+In general, we tend on the side of merging things with nits (i.e.,
+anything sub-optimal that isn't absolutely required to be right) and
+then opening issues to leaving pull requests open indefinitely waiting
+on the original submitter to fix them; when tests are being upstreamed
+from vendors it is frequently the case that the author has moved on to
+working on other things as tests frequently only get pushed upstream
+once the code lands in their implementation.
+
+To assist with test reviews, a [review checklist](checklist) is available.
+
+[GitHub.com allows reviewers to formally signal their approval of a pull
+request through a dedicated user
+interface.](https://help.github.com/en/articles/about-pull-request-reviews)
+Every pull request submitted to WPT must be approved by at least one project
+collaborator before it can be merged.
+
+## Notifications
+
+META.yml files are used to indicate who should be notified of pull
+requests.  If you are interested in receiving notifications of proposed
+changes to tests in a given directory, feel free to add your GitHub account
+username to the `suggested_reviewers` list in the META.yml file.
+
+## Finding contributions to review
+
+Here are a few search filters to find things to review:
+
+* [Open PRs (excluding vendor exports)](https://github.com/web-platform-tests/wpt/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+-label%3A%22mozilla%3Agecko-sync%22+-label%3A%22chromium-export%22+-label%3A%22webkit-export%22+-label%3A%22servo-export%22+-label%3Avendor-imports)
+* [Reviewed but still open PRs (excluding vendor exports)](https://github.com/web-platform-tests/wpt/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+-label%3Amozilla%3Agecko-sync+-label%3Achromium-export+-label%3Awebkit-export+-label%3Aservo-export+-label%3Avendor-imports+review%3Aapproved+-label%3A%22do+not+merge+yet%22+-label%3A%22status%3Aneeds-spec-decision%22) (Merge? Something left to fix? Ping other reviewer?)
+* [Open PRs without reviewers](https://github.com/web-platform-tests/wpt/pulls?q=is%3Apr+is%3Aopen+label%3Astatus%3Aneeds-reviewers)
+* [Open PRs with label `infra` (excluding vendor exports)](https://github.com/web-platform-tests/wpt/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+label%3Ainfra+-label%3A%22mozilla%3Agecko-sync%22+-label%3A%22chromium-export%22+-label%3A%22webkit-export%22+-label%3A%22servo-export%22+-label%3Avendor-imports)
+* [Open PRs with label `docs` (excluding vendor exports)](https://github.com/web-platform-tests/wpt/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+label%3Adocs+-label%3A%22mozilla%3Agecko-sync%22+-label%3A%22chromium-export%22+-label%3A%22webkit-export%22+-label%3A%22servo-export%22+-label%3Avendor-imports)
diff --git a/third_party/blink/web_tests/external/wpt/docs/reviewing-tests/reverting.md b/third_party/blink/web_tests/external/wpt/docs/reviewing-tests/reverting.md
new file mode 100644
index 0000000..277ccb0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/reviewing-tests/reverting.md
@@ -0,0 +1,28 @@
+# Reverting Changes
+
+Testing is imperfect and from time to time changes are merged into master which
+break things for users of web-platform-tests. Such breakage can include:
+
+  * Failures in Travis or Taskcluster runs for this repository, either on the
+    master branch or on pull requests following the breaking change.
+
+  * Breakage in browser engine repositories which import and run
+    web-platform-tests, such as Chromium, Edge, Gecko, Servo and WebKit.
+
+  * Breakage in results collections systems for results dashboards, such as
+    [wpt.fyi](https://wpt.fyi).
+
+  * Breakage in supplemental tooling used by working groups, such as the
+    [CSS build system][].
+
+When such breakage happens, if the maintainers of the affected systems request
+it, pull requests to revert the original change should normally be approved and
+merged as soon as possible. (When the original change itself was fixing a
+serious problem, it's a judgement call, but prefer the fastest path to a stable
+state acceptable to everyone.)
+
+Once a revert has happened, the maintainers of the affected systems are
+expected to work with the original patch author to resolve the problem so that
+the change can be relanded. A reasonable timeframe to do so is within one week.
+
+[CSS build system]: https://github.com/web-platform-tests/wpt/tree/master/css/tools
diff --git a/third_party/blink/web_tests/external/wpt/docs/running-tests/android_webview.md b/third_party/blink/web_tests/external/wpt/docs/running-tests/android_webview.md
new file mode 100644
index 0000000..4a86814
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/running-tests/android_webview.md
@@ -0,0 +1,51 @@
+# Android WebView
+
+To run WPT on WebView on an Android device, some additional set-up is required.
+
+Currently, Android WebView support is experimental.
+
+## Prerequisites
+
+Please check [Chrome for Android](chrome_android.md) for the common instructions for Android support first.
+
+Ensure you have a userdebug or eng Android build installed on the device.
+
+Install an up-to-date version of system webview shell:
+1. Go to [chromium-browser-snapshots](https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Android/)
+2. Find the subdirectory with the highest number and click it, this number can be found
+   in the "Commit Position" column of row "LAST_CHANGE" (at bottom of page).
+3. Download `chrome-android.zip` file and unzip it.
+4. Install `SystemWebViewShell.apk`.
+5. On emulator, system webview shell may already be installed by default. Then you may need to remove the existing apk:
+   * Choose a userdebug build.
+   * Run an emulator with
+     [writable system partition from command line](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/android_emulator.md/)
+
+If you have an issue with ChromeDriver version mismatch, try one of the following:
+  * Try removing `_venv/bin/chromedriver` such that wpt runner can install a matching version
+  automatically. Failing that, please check your environment path and make
+  sure that no other ChromeDriver is used.
+  * Download the [ChromeDriver binary](https://chromedriver.chromium.org/) matching your WebView's major version and specify it on the command line
+    ```
+    ./wpt run --webdriver-binary <binary path> ...
+    ```
+
+Configure host remap rules in the [webview commandline file](https://cs.chromium.org/chromium/src/android_webview/docs/commandline-flags.md?l=57):
+```
+adb shell "echo '_ --host-resolver-rules=\"MAP nonexistent.*.test ~NOTFOUND, MAP *.test 127.0.0.1\"' > /data/local/tmp/webview-command-line"
+```
+
+Ensure that `adb` can be found on your system's PATH.
+
+## Running Tests
+
+Example command line:
+
+```bash
+./wpt run --test-type=testharness android_webview <TESTS>
+```
+
+* Note that there is no support for channel or automatic installation. The test
+  will be run against the current WebView version installed on the device.
+
+* Reftests are not supported at the moment.
diff --git a/third_party/blink/web_tests/external/wpt/docs/running-tests/chrome.md b/third_party/blink/web_tests/external/wpt/docs/running-tests/chrome.md
new file mode 100644
index 0000000..c56d3c5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/running-tests/chrome.md
@@ -0,0 +1,30 @@
+# Chrome
+
+When running Chrome, there are some useful command line arguments.
+
+You can inform `wpt` of the release channel of Chrome using `--channel`.
+`wpt` is able to find the correct binary in the following cases:
+* On Linux for stable, beta and dev channels if
+  `google-chrome-{stable,beta,unstable}` are in `PATH`;
+* On Mac for stable and canary channels if the official DMGs are installed.
+
+In other cases, you will need to specify the path to the Chrome binary with
+`--binary`. For example:
+
+```bash
+./wpt run --channel dev --binary /path/to/non-default/google-chrome chrome
+```
+
+Note: when the channel is "dev", `wpt` will *automatically* enable all
+[experimental web platform features][1]
+(chrome://flags/#enable-experimental-web-platform-features) by passing
+`--enable-experimental-web-platform-features` to Chrome.
+
+If you want to enable a specific [runtime enabled feature][1], use
+`--binary-arg` to specify the flag(s) that you want to pass to Chrome:
+
+```bash
+./wpt run --binary-arg=--enable-blink-features=AsyncClipboard chrome clipboard-apis/
+```
+
+[1]: https://www.chromium.org/blink/runtime-enabled-features
diff --git a/third_party/blink/web_tests/external/wpt/docs/running-tests/chrome_android.md b/third_party/blink/web_tests/external/wpt/docs/running-tests/chrome_android.md
new file mode 100644
index 0000000..a216a8a6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/running-tests/chrome_android.md
@@ -0,0 +1,22 @@
+# Chrome for Android
+
+To run WPT on Chrome on an Android device, some additional set up is required.
+
+As with usual Android development, you need to have `adb` and be able to
+connect to the device. Run `adb devices` to verify.
+
+Currently, Android support is a prototype with some known issues:
+
+* If you have previously run `./wpt run` against Chrome, you might need to
+  remove `_venv/bin/chromedriver` so that we can install the correct
+  ChromeDriver corresponding to your Chrome for Android version.
+* We do not support reftests at the moment.
+* You will need to manually kill Chrome (all channels) before running tests.
+
+Note: rooting the device or installing a root CA is no longer required.
+
+Example (assuming you have Chrome Canary installed on your phone):
+
+```bash
+./wpt run --test-type=testharness --channel=canary chrome_android TESTS
+```
diff --git a/third_party/blink/web_tests/external/wpt/docs/running-tests/command-line-arguments.md b/third_party/blink/web_tests/external/wpt/docs/running-tests/command-line-arguments.md
new file mode 100644
index 0000000..598c9da
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/running-tests/command-line-arguments.md
@@ -0,0 +1,14 @@
+# Command-Line Arguments
+
+The `wpt` command-line application offers a number of features for interacting
+with WPT. The functionality is organized into "sub-commands", and each accepts
+a different set of command-line arguments.
+
+This page documents all of the available sub-commands and associated arguments.
+
+```eval_rst
+.. argparse::
+   :module: tools.wpt.wpt
+   :func: create_complete_parser
+   :prog: wpt
+```
diff --git a/third_party/blink/web_tests/external/wpt/docs/running-tests/custom-runner.md b/third_party/blink/web_tests/external/wpt/docs/running-tests/custom-runner.md
new file mode 100644
index 0000000..4e860ed
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/running-tests/custom-runner.md
@@ -0,0 +1,22 @@
+# Writing Your Own Runner
+
+Most test runners have two stages: finding all tests, followed by
+executing them (or a subset thereof).
+
+To find all tests in the repository, it is **strongly** recommended to
+use the included `wpt manifest` tool: the required behaviors are more
+complex than what are documented (especially when it comes to
+precedence of the various possibilities and some undocumented legacy
+ways to define test types), and hence its behavior should be
+considered the canonical definition of how to enumerate tests and find
+their type in the repository.
+
+For test execution, please read the documentation for the various test types
+very carefully and then check your understanding on
+the [mailing list][public-test-infra] or [IRC][] ([webclient][web irc], join
+channel `#testing`). It's possible edge-case behavior isn't properly
+documented!
+
+[public-test-infra]: https://lists.w3.org/Archives/Public/public-test-infra/
+[IRC]: irc://irc.w3.org:6667/testing
+[web irc]: http://irc.w3.org
diff --git a/third_party/blink/web_tests/external/wpt/docs/running-tests/from-ci.md b/third_party/blink/web_tests/external/wpt/docs/running-tests/from-ci.md
new file mode 100644
index 0000000..9ea142bb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/running-tests/from-ci.md
@@ -0,0 +1,32 @@
+# Running Tests on CI
+
+Contributors with write access to the repository can trigger full runs in the
+same CI systems used to produce results for [wpt.fyi](https://wpt.fyi). The runs
+are triggered by pushing to branch names on the form `triggers/$browser_$channel`
+and the results will be automatically submitted to wpt.fyi.
+
+This is useful when making infrastructure changes that could affect very many
+tests, in order to avoid regressions.
+
+Note: Full runs use a lot of CI resources, so please take care to not trigger
+them more than necessary.
+
+Instructions:
+
+ * Base your changes on a commit for which there are already results in wpt.fyi.
+
+ * Determine which branch name to push to by looking for `refs/heads/triggers/`
+   in `.azure-pipelines.yml` and `.taskcluster.yml`. For example, to trigger a
+   full run of Safari Technology Preview, the branch name is
+   `triggers/safari_preview`.
+
+ * Force push to the branch, for example:
+   `git push --force-with-lease origin HEAD:triggers/safari_preview`.
+   The `--force-with-lease` argument is to detect if someone else has just
+   pushed. When this happens wait for the checkout step of their triggered run
+   to finish before you force push again.
+
+You can see if the run started from the commit status on GitHub's commits listing
+([example](https://github.com/web-platform-tests/wpt/commits/triggers/safari_preview))
+and if successful the results will show up on wpt.fyi within 10 minutes
+([example](https://wpt.fyi/runs?product=safari)).
diff --git a/third_party/blink/web_tests/external/wpt/docs/running-tests/from-local-system.md b/third_party/blink/web_tests/external/wpt/docs/running-tests/from-local-system.md
new file mode 100644
index 0000000..8c71e535
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/running-tests/from-local-system.md
@@ -0,0 +1,170 @@
+# Running Tests from the Local System
+
+The tests are designed to be run from your local computer.
+
+## System Setup
+
+Running the tests requires `python`, `pip` and `virtualenv`, as well as updating
+the system `hosts` file.
+
+Note that Python 2.7 is required. Using Python 3 is not supported.
+
+The required setup is different depending on your operating system.
+
+### Linux Setup
+
+If not already present, use the system package manager to install `python`,
+`pip` and `virtualenv`.
+
+On Debian or Ubuntu:
+
+```bash
+sudo apt-get install python python-pip virtualenv
+```
+
+### macOS Setup
+
+The system-provided Python can be used, while `pip` and `virtualenv` can be
+installed for the user only:
+
+```bash
+python -m ensurepip --user
+export PATH="$PATH:$HOME/Library/Python/2.7/bin"
+pip install --user virtualenv
+```
+
+To make the `PATH` change persistent, add it to your `~/.bash_profile` file or
+wherever you currently set your PATH.
+
+See also [additional setup required to run Safari](safari.md).
+
+### Windows Setup
+**Note:** In general, Windows Subsystem for Linux will provide the smoothest
+user experience for running web-platform-tests on Windows, where installation
+and usage are similar to Linux.
+
+Download and install [Python 2.7](https://www.python.org/downloads). The
+installer includes `pip` by default.
+
+Add `C:\Python27` and `C:\Python27\Scripts` to your `%Path%`
+[environment variable](http://www.computerhope.com/issues/ch000549.htm).
+
+Finally, install `virtualenv`:
+
+```bash
+pip install virtualenv
+```
+
+The standard Windows shell requires that all `wpt` commands are prefixed
+by the Python binary i.e. assuming `python` is on your path the server is
+started using:
+
+```bash
+python wpt serve
+```
+
+### `hosts` File Setup
+
+To get the tests running, you need to set up the test domains in your
+[`hosts` file](http://en.wikipedia.org/wiki/Hosts_%28file%29%23Location_in_the_file_system).
+
+On Linux, macOS or other UNIX-like system:
+
+```bash
+./wpt make-hosts-file | sudo tee -a /etc/hosts
+```
+
+And on Windows (this must be run in a PowerShell session with Administrator privileges):
+
+```
+python wpt make-hosts-file | Out-File $env:SystemRoot\System32\drivers\etc\hosts -Encoding ascii -Append
+```
+
+If you are behind a proxy, you also need to make sure the domains above are
+excluded from your proxy lookups.
+
+## Via the browser
+
+The test environment can then be started using
+
+    ./wpt serve
+
+This will start HTTP servers on two ports and a websockets server on
+one port. By default the web servers start on ports 8000 and 8443 and the other
+ports are randomly-chosen free ports. Tests must be loaded from the
+*first* HTTP server in the output. To change the ports,
+create a `config.json` file in the wpt root directory, and add
+port definitions of your choice e.g.:
+
+```
+{
+  "ports": {
+    "http": [1234, "auto"],
+    "https":[5678]
+  }
+}
+```
+
+After your `hosts` file is configured, the servers will be locally accessible at:
+
+http://web-platform.test:8000/<br>
+https://web-platform.test:8443/ *
+
+To use the web-based runner point your browser to:
+
+http://web-platform.test:8000/tools/runner/index.html<br>
+https://web-platform.test:8443/tools/runner/index.html *
+
+This server has all the capabilities of the publicly-deployed version--see
+[Running the Tests from the Web](from-web.md).
+
+\**See [Trusting Root CA](../tools/certs/README.md)*
+
+## Via the command line
+
+Many tests can be automatically executed in a new browser instance using
+
+    ./wpt run [browsername] [tests]
+
+This will automatically load the tests in the chosen browser and extract the
+test results. For example to run the `dom/historical.html` tests in a local
+copy of Chrome:
+
+    ./wpt run chrome dom/historical.html
+
+Or to run in a specified copy of Firefox:
+
+    ./wpt run --binary ~/local/firefox/firefox firefox dom/historical.html
+
+For details on the supported products and a large number of other options for
+customising the test run:
+
+    ./wpt run --help
+
+[A complete listing of the command-line arguments is available
+here](command-line-arguments.md).
+
+```eval_rst
+.. toctree::
+   :hidden:
+
+   command-line-arguments
+```
+
+Additional browser-specific documentation:
+
+```eval_rst
+.. toctree::
+
+  chrome
+  chrome_android
+  android_webview
+  safari
+  webkitgtk_minibrowser
+```
+
+For use in continuous integration systems, and other scenarios where regression
+tracking is required, the command-line interface supports storing and loading
+the expected result of each test in a test run. See [Expectations
+Data](../../tools/wptrunner/docs/expectation) for more information on creating
+and maintaining these files.
diff --git a/third_party/blink/web_tests/external/wpt/docs/running-tests/from-web.md b/third_party/blink/web_tests/external/wpt/docs/running-tests/from-web.md
new file mode 100644
index 0000000..fae4c961
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/running-tests/from-web.md
@@ -0,0 +1,22 @@
+# Running Tests from the Web
+
+Tests that have been merged on GitHub are mirrored at [http://w3c-test.org/][w3c-test].
+[On properly-configured systems](from-local-system), local files may also be
+served from the URL [http://web-platform.test](http://web-platform.test).
+
+For running multiple tests inside a browser, there is a test runner
+located at `/tools/runner/index.html`.
+
+This allows all the tests, or those matching a specific prefix
+(e.g. all tests under `/dom/`) to be run. For testharness.js tests,
+the results will be automatically collected, while the runner
+provides a simple UI for manually comparing reftest rendering and
+running manual tests.
+
+Note, however, it does not currently handle more complex reftests with
+more than one reference involved.
+
+Because it runs entirely in-browser, this runner cannot deal with
+edge-cases like tests that cause the browser to crash or hang.
+
+[w3c-test]: http://w3c-test.org
diff --git a/third_party/blink/web_tests/external/wpt/docs/running-tests/index.md b/third_party/blink/web_tests/external/wpt/docs/running-tests/index.md
new file mode 100644
index 0000000..17b361d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/running-tests/index.md
@@ -0,0 +1,24 @@
+# Running Tests
+
+```eval_rst
+.. toctree::
+
+   from-web
+   from-local-system
+   from-ci
+   custom-runner
+   ../tools/certs/README.md
+```
+
+The simplest way to run the tests is via the public website. More detail on
+that approach is available in [Running tests from the Web](from-web).
+
+Contributors who are interested in modifying and creating tests should refer to
+[Running Tests from the Local System](from-local-system).
+
+Contributors with write access to the repository can also trigger full runs
+in our CI setups, see [Running Tests on CI](from-ci).
+
+Advanced use cases may call for a customized method of executing the tests.
+Guidelines for writing a custom "runner" are available at [Writing Your Own
+Runner](custom-runner).
diff --git a/third_party/blink/web_tests/external/wpt/docs/running-tests/safari.md b/third_party/blink/web_tests/external/wpt/docs/running-tests/safari.md
new file mode 100644
index 0000000..eed5225
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/running-tests/safari.md
@@ -0,0 +1,47 @@
+# Safari
+
+To run Safari on macOS, some manual setup is required. Some steps are different
+for Safari and Safari Technology Preview.
+
+  * Allow Safari to be controlled by SafariDriver:
+    * `safaridriver --enable` or
+    * `"/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver" --enable`
+
+  * Allow pop-up windows:
+    * `defaults write com.apple.Safari WebKitJavaScriptCanOpenWindowsAutomatically 1` or
+    * `defaults write com.apple.SafariTechnologyPreview WebKitJavaScriptCanOpenWindowsAutomatically 1`
+
+  * Turn on additional experimental features Safari Technology Preview:
+    * `defaults write com.apple.SafariTechnologyPreview ExperimentalServerTimingEnabled 1`
+
+  * Trust the certificate:
+    * `security add-trusted-cert -k "$(security default-keychain | cut -d\" -f2)" tools/certs/cacert.pem`
+
+  * Set `no_proxy='*'` in your environment. This is a
+    workaround for a known
+    [macOS High Sierra issue](https://github.com/web-platform-tests/wpt/issues/9007).
+
+Now, run the tests using the `safari` product:
+```
+./wpt run safari [test_list]
+```
+
+This will use the `safaridriver` found on the path, which will be stable Safari.
+To run Safari Technology Preview instead, use the `--channel=preview` argument:
+```
+./wpt run --channel=preview safari [test_list]
+```
+
+## Debugging
+
+To debug problems with `safaridriver`, add the `--webdriver-arg=--diagnose`
+argument:
+```
+./wpt run --channel=preview --webdriver-arg=--diagnose safari [test_list]
+```
+
+The logs will be in `~/Library/Logs/com.apple.WebDriver/`.
+See `man safaridriver` for more information.
+
+To enable safaridriver diagnostics in Azure Pipelines, set
+`safaridriver_diagnose` to `true` in `.azure-pipelines.yml`.
diff --git a/third_party/blink/web_tests/external/wpt/docs/running-tests/webkitgtk_minibrowser.md b/third_party/blink/web_tests/external/wpt/docs/running-tests/webkitgtk_minibrowser.md
new file mode 100644
index 0000000..7aac81e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/running-tests/webkitgtk_minibrowser.md
@@ -0,0 +1,20 @@
+# WebKitGTK MiniBrowser
+
+
+To be able to run tests with the WebKitGTK MiniBrowser you need the
+following packages installed:
+
+* Fedora: `webkit2gtk3-devel`
+* Debian or Ubuntu: `webkit2gtk-driver`
+
+
+The WebKitGTK MiniBrowser is not installed on the default binary path.
+The `wpt` script will try to automatically locate it, but if you need
+to run it manually you can find it on any of this paths:
+
+* Fedora: `/usr/libexec/webkit2gtk-4.0/MiniBrowser`
+* Debian or Ubuntu: `/usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/MiniBrowser`
+  * Note: if the machine architecture is not `x86_64`, then it will be located
+    inside:
+    `/usr/lib/${TRIPLET}/webkit2gtk-4.0/MiniBrowser`
+    where `TRIPLET=$(gcc -dumpmachine)`
diff --git a/third_party/blink/web_tests/external/wpt/docs/test-suite-design.md b/third_party/blink/web_tests/external/wpt/docs/test-suite-design.md
new file mode 100644
index 0000000..6a104e2f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/test-suite-design.md
@@ -0,0 +1,79 @@
+# Test Suite Design
+
+The vast majority of the test suite is formed of HTML pages, which can
+be loaded in a browser and either programmatically provide a result or
+provide a set of steps to run the test and obtain the result.
+
+The tests are, in general, short, cross-platform, and self-contained,
+and should be easy to run in any browser.
+
+
+## Test Layout
+
+Most of the repository's top-level directories hold tests for specific web
+standards. For [W3C specs](https://www.w3.org/standards/), these directories
+are typically named after the shortname of the spec (i.e. the name used for
+snapshot publications under `/TR/`); for [WHATWG
+specs](https://spec.whatwg.org/), they are typically named after the subdomain
+of the spec (i.e. trimming `.spec.whatwg.org` from the URL); for other specs,
+something deemed sensible is used. The `css/` directory contains test suites
+for [the CSS Working Group
+specifications](https://www.w3.org/Style/CSS/current-work).
+
+Within the specification-specific directory there are two common ways
+of laying out tests: the first is a flat structure which is sometimes
+adopted for very short specifications; the alternative is a nested
+structure with each subdirectory corresponding to the id of a heading
+in the specification. The latter provides some implicit metadata about
+the part of a specification being tested according to its location in
+the filesystem, and is preferred for larger specifications.
+
+For example, tests in HTML for ["The History
+interface"](https://html.spec.whatwg.org/multipage/history.html#the-history-interface)
+are located in `html/browsers/history/the-history-interface/`.
+
+Many directories also include a file named `META.yml`. This file may define any
+of the following properties:
+
+- `spec` - a link to the specification covered by the tests in the directory
+- `suggested_reviewers` - a list of GitHub account username belonging to
+  people who are notified when pull requests modify files in the directory
+
+Various resources that tests depend on are in `common`, `images`, `fonts`,
+`media`, and `resources`.
+
+## Test Types
+
+Tests in this project use a few different approaches to verify expected
+behavior. The tests can be classified based on the way they express
+expectations:
+
+* Rendering tests ensure that the browser graphically displays pages as
+  expected. There are a few different ways this is done:
+
+  * [Reftests][] render two (or more) web pages and combine them with equality
+    assertions about their rendering (e.g., `A.html` and `B.html` must render
+    identically), run either by the user switching between tabs/windows and
+    trying to observe differences or through [automated
+    scripts][running-from-local-system].
+
+  * [Visual tests][visual] display a page where the result is determined either
+    by a human looking at it or by comparing it with a saved screenshot for
+    that user agent on that platform.
+
+* [testharness.js][] tests verify that JavaScript interfaces behave as
+  expected. They get their name from the JavaScript harness that's used to
+  execute them.
+
+* [wdspec][] tests are written in Python and test [the WebDriver browser
+  automation protocol](https://w3c.github.io/webdriver/)
+
+* [Manual tests][manual] rely on a human to run them and determine their
+  result.
+
+[reftests]: writing-tests/reftests
+[testharness.js]: writing-tests/testharness
+[visual]: writing-tests/visual
+[manual]: writing-tests/manual
+[running-from-local-system]: running-tests/from-local-system
+[wdspec]: writing-tests/wdspec
diff --git a/third_party/blink/web_tests/external/wpt/docs/wpt_lint_rules.py b/third_party/blink/web_tests/external/wpt/docs/wpt_lint_rules.py
new file mode 100644
index 0000000..a5eed50
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/wpt_lint_rules.py
@@ -0,0 +1,78 @@
+from docutils.parsers.rst import Directive, nodes
+from docutils.utils import new_document
+from recommonmark.parser import CommonMarkParser
+import importlib
+import textwrap
+
+class WPTLintRules(Directive):
+    """A docutils directive to generate documentation for the
+    web-platform-test-test's linting tool from its source code. Requires a
+    single argument: a Python module specifier for a file which declares
+    linting rules."""
+    has_content = True
+    required_arguments = 1
+    optional_arguments = 0
+    _md_parser = CommonMarkParser()
+
+    @staticmethod
+    def _parse_markdown(markdown):
+        WPTLintRules._md_parser.parse(markdown, new_document("<string>"))
+        return WPTLintRules._md_parser.document.children[0]
+
+    @property
+    def module_specifier(self):
+        return self.arguments[0]
+
+    def _get_rules(self):
+        try:
+            module = importlib.import_module(self.module_specifier)
+        except ImportError:
+            raise ImportError(
+                """wpt-lint-rules: unable to resolve the module at "{}".""".format(self.module_specifier)
+            )
+
+        for binding_name, value in module.__dict__.iteritems():
+            if hasattr(value, "__abstractmethods__") and len(value.__abstractmethods__):
+                continue
+
+            description = getattr(value, "description", None)
+            name = getattr(value, "name", None)
+            to_fix = getattr(value, "to_fix", None)
+
+            if description is None:
+                continue
+
+            if to_fix is not None:
+                to_fix = textwrap.dedent(to_fix)
+
+            yield {
+                "name": name,
+                "description": textwrap.dedent(description),
+                "to_fix": to_fix
+            }
+
+
+    def run(self):
+        definition_list = nodes.definition_list()
+
+        for rule in sorted(self._get_rules(), key=lambda rule: rule['name']):
+            item = nodes.definition_list_item()
+            definition = nodes.definition()
+            term = nodes.term()
+            item += term
+            item += definition
+            definition_list += item
+
+            term += nodes.literal(text=rule["name"])
+            definition += WPTLintRules._parse_markdown(rule["description"])
+
+            if rule["to_fix"]:
+                definition += nodes.strong(text="To fix:")
+                definition += WPTLintRules._parse_markdown(rule["to_fix"])
+
+        if len(definition_list.children) == 0:
+            raise Exception(
+                """wpt-lint-rules: no linting rules found at "{}".""".format(self.module_specifier)
+            )
+
+        return [definition_list]
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/ahem.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/ahem.md
new file mode 100644
index 0000000..30a3fcd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/ahem.md
@@ -0,0 +1,78 @@
+# The Ahem Font
+
+A font called [Ahem][ahem-readme] has been developed which consists of
+some very well defined glyphs of precise sizes and shapes; it is
+especially useful for testing font and text properties. Installation
+instructions are available in [Running Tests from the Local
+System](../running-tests/from-local-system).
+
+The font's em-square is exactly square. Its ascent and descent
+combined is exactly the size of the em square; this means that the
+font's extent is exactly the same as its line-height, meaning that it
+can be exactly aligned with padding, borders, margins, and so
+forth. Its alphabetic baseline is 0.2em above its bottom, and 0.8em
+below its top.
+
+The font has four glyphs:
+
+* X (U+0058):  A square exactly 1em in height and width.
+* p (U+0070):  A rectangle exactly 0.2em high, 1em wide, and aligned so
+that its top is flush with the baseline.
+* É (U+00C9):  A rectangle exactly 0.8em high, 1em wide, and aligned so
+that its bottom is flush with the baseline.
+* [space] (U+0020):  A transparent space exactly 1em high and wide.
+
+Most other US-ASCII characters in the font have the same glyph as X.
+
+## Usage
+Ahem should be loaded in tests as a web font. To simplify this, a test can
+link to the `/fonts/ahem.css` stylesheet:
+
+```
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+```
+
+If the test uses the Ahem font, make sure its computed font-size is a
+multiple of 5px, otherwise baseline alignment may be rendered
+inconsistently. A minimum computed font-size of 20px is suggested.
+
+An explicit (i.e., not `normal`) line-height should also always be
+used, with the difference between the computed line-height and
+font-size being divisible by 2. In the common case, having the same
+value for both is desirable.
+
+Other font properties should make sure they have their default values;
+as such, the `font` shorthand should normally be used.
+
+As a result, what is typically recommended is:
+
+
+``` css
+div {
+  font: 25px/1 Ahem;
+}
+```
+
+Some things to avoid:
+
+``` css
+div {
+  font: 1em/1em Ahem;  /* computed font-size is typically 16px and potentially
+                          affected by parent elements */
+}
+
+div {
+  font: 20px Ahem;  /* computed line-height value is normal */
+}
+
+div {
+  /* doesn't use font shorthand; font-weight and font-style are inherited */
+  font-family: Ahem;
+  font-size: 25px;
+  line-height: 50px;  /* the difference between computed line-height and
+                         computed font-size is not divisible by 2
+                         (50 - 25 = 25; 25 / 2 = 12.5). */
+}
+```
+
+[ahem-readme]: https://www.w3.org/Style/CSS/Test/Fonts/Ahem/README
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/assumptions.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/assumptions.md
new file mode 100644
index 0000000..5afa416
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/assumptions.md
@@ -0,0 +1,40 @@
+# Test Assumptions
+
+The tests make a number of assumptions of the user agent, and new
+tests can freely rely on these assumptions being true:
+
+ * The device is a full-color device.
+ * The device has a viewport width of at least 800px.
+ * The UA imposes no minimum font size.
+ * The `medium` `font-size` computes to 16px.
+ * The canvas background is `white`.
+ * The initial value of `color` is `black`.
+ * The user stylesheet is empty (except where indicated by the tests).
+ * The device is interactive and uses scroll bars.
+ * The HTML `div` element is assigned `display: block;`, the
+   `unicode-bidi` property may be declared, and no other property
+   declarations.
+   <!-- unicode-bidi: isolate should be required; we currently don't
+   assume this because Chrome and Safari are yet to ship this: see
+   https://bugs.chromium.org/p/chromium/issues/detail?id=296863 and
+   https://bugs.webkit.org/show_bug.cgi?id=65617 -->
+ * The HTML `span` element is assigned `display: inline;` and no other
+   property declaration.
+ * The HTML `p` element is assigned `display: block;`
+ * The HTML `li` element is assigned `display: list-item;`
+ * The HTML `table` elements `table`, `tbody`, `tr`, and `td` are
+   assigned the `display` values `table`, `table-row-group`,
+   `table-row`, and `table-cell`, respectively.
+ * The UA implements reasonable line-breaking behavior; e.g., it is
+   assumed that spaces between alphanumeric characters provide line
+   breaking opportunities and that UAs will not break at every
+   opportunity, but only near the end of a line unless a line break is
+   forced.
+
+Tests for printing behavior make some further assumptions:
+
+ * The UA is set to print background colors and, if it supports
+   graphics, background images.
+ * The UA implements reasonable page-breaking behavior; e.g., it is
+   assumed that UAs will not break at every opportunity, but only near
+   the end of a page unless a page break is forced.
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/crashtest.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/crashtest.md
new file mode 100644
index 0000000..0166bde
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/crashtest.md
@@ -0,0 +1,29 @@
+# crashtest tests
+
+Crash tests are used to ensure that a document can be loaded without
+crashing or experiencing other low-level issues that may be checked by
+implementation-specific tooling (e.g. leaks, asserts, or sanitizer
+failures).
+
+Crashtests are identified by the string `-crash` in the filename immediately
+before the extension, or by being in a directory called `crashtests`. Examples:
+
+- `css/css-foo/bar-crash.html` is a crash test
+- `css/css-foo/crashtests/bar.html` is a crash test
+- `css/css-foo/bar-crash-001.html` is **not** a crash test
+
+The simplest crashtest is a single HTML file with any content. The
+test passes if the load event is reached, and the browser finishes
+painting, without terminating.
+
+In some cases crashtests may need to perform work after the initial page load.
+In this case the test may specify a `class=test-wait` attribute on the root
+element. The test will not complete until that attribute is removed from the
+root. At the time when the test would otherwise have ended a `TestRendered`
+event is emitted; test authors can use this event to perform modifications that
+are guaranteed not to be batched with the initial paint. This matches the
+behaviour of [reftests](reftests).
+
+Note that crash tests **do not** need to include `testharness.js` or use any of
+the [testharness API](testharness-api.md) (e.g. they do not need to declare a
+`test(..)`).
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/css-metadata.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/css-metadata.md
new file mode 100644
index 0000000..9d8ebedd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/css-metadata.md
@@ -0,0 +1,188 @@
+# CSS Metadata
+
+CSS tests have some additional metadata.
+
+### Specification Links
+
+Each test **requires** at least one link to specifications:
+
+``` html
+<link rel="help" href="RELEVANT_SPEC_SECTION" />
+```
+
+The specification link elements provide a way to align the test with
+information in the specification being tested.
+
+* Links should link to relevant sections within the specification
+* Use the anchors from the specification's Table of Contents
+* A test can have multiple specification links
+  * Always list the primary section that is being tested as the
+    first item in the list of specification links
+  * Order the list from the most used/specific to least used/specific
+  * There is no need to list common incidental features like the
+    color green if it is being used to validate the test unless the
+    case is specifically testing the color green
+* If the test is part of multiple test suites, link to the relevant
+  sections of each spec.
+
+Example 1:
+
+``` html
+<link rel="help"
+href="https://www.w3.org/TR/CSS21/text.html#alignment-prop" />
+```
+
+Example 2:
+
+``` html
+<link rel="help"
+href="https://www.w3.org/TR/CSS21/text.html#alignment-prop" />
+<link rel="help" href="https://www.w3.org/TR/CSS21/visudet.html#q7" />
+<link rel="help"
+href="https://www.w3.org/TR/CSS21/visudet.html#line-height" />
+<link rel="help"
+href="https://www.w3.org/TR/CSS21/colors.html#background-properties" />
+```
+
+### Requirement Flags
+
+If a test has any of the following requirements, a meta element can be added
+to include the corresponding flags (tokens):
+
+<table>
+<tr>
+  <th>Token</th>
+  <th>Description</th>
+</tr>
+<tr>
+  <td>asis</td>
+  <td>The test has particular markup formatting requirements and
+    cannot be re-serialized.</td>
+</tr>
+<tr>
+  <td>HTMLonly</td>
+  <td>Test case is only valid for HTML</td>
+</tr>
+<tr>
+  <td>invalid</td>
+  <td>Tests handling of invalid CSS. Note: This case contains CSS
+     properties and syntax that may not validate.</td>
+</tr>
+<tr>
+  <td>may</td>
+  <td>Behavior tested is preferred but OPTIONAL.
+  <a href="https://www.ietf.org/rfc/rfc2119.txt">[RFC2119]</a></td>
+</tr>
+<tr>
+  <td>nonHTML</td>
+  <td>Test case is only valid for formats besides HTML (e.g. XHTML
+    or arbitrary XML)</td>
+</tr>
+<tr>
+  <td>paged</td>
+  <td>Only valid for paged media</td>
+</tr>
+<tr>
+  <td>scroll</td>
+  <td>Only valid for continuous (scrolling) media</td>
+</tr>
+<tr>
+  <td>should</td>
+  <td>Behavior tested is RECOMMENDED, but not REQUIRED. <a
+    href="https://www.ietf.org/rfc/rfc2119.txt">[RFC2119]</a></td>
+</tr>
+</table>
+
+The following flags are **deprecated** and should not be declared by new tests.
+Tests which satisfy the described criteria should simply be designated as
+"manual" using [the `-manual` file name flag](file-names).
+
+<table>
+<tr>
+  <th>Token</th>
+  <th>Description</th>
+</tr>
+<tr>
+  <td>animated</td>
+  <td>Test is animated in final state. (Cannot be verified using
+    reftests/screenshots.)</td>
+</tr>
+<tr>
+  <td>font</td>
+  <td>Requires a specific font to be installed at the OS level. (A link to the
+      font to be installed must be provided; this is not needed if only web
+      fonts are used.)</td>
+</tr>
+<tr>
+  <td>history</td>
+  <td>User agent session history is required. Testing :visited is a
+    good example where this may be used.</td>
+</tr>
+<tr>
+  <td>interact</td>
+  <td>Requires human interaction (such as for testing scrolling
+    behavior)</td>
+</tr>
+<tr>
+  <td>speech</td>
+  <td>Device supports audio output. Text-to-speech (TTS) engine
+    installed</td>
+</tr>
+<tr>
+  <td>userstyle</td>
+  <td>Requires a user style sheet to be set</td>
+</tr>
+</table>
+
+
+Example 1 (one token applies):
+
+``` html
+<meta name="flags" content="invalid" />
+```
+
+Example 2 (multiple tokens apply):
+
+``` html
+<meta name="flags" content="asis HTMLonly may" />
+```
+
+### Test Assertions
+
+``` html
+<meta name="assert" content="TEST ASSERTION" />
+```
+
+This element should contain a complete detailed statement expressing
+what specifically the test is attempting to prove. If the assertion
+is only valid in certain cases, those conditions should be described
+in the statement.
+
+The assertion should not be:
+
+* A copy of the title text
+* A copy of the test verification instructions
+* A duplicate of another assertion in the test suite
+* A line or reference from the CSS specification unless that line is
+  a complete assertion when taken out of context.
+
+The test assertion is **optional**, but is highly recommended.
+It helps the reviewer understand
+the goal of the test so that he or she can make sure it is being
+tested correctly. Also, in case a problem is found with the test
+later, the testing method (e.g. using `color` to determine pass/fail)
+can be changed (e.g. to using `background-color`) while preserving
+the intent of the test (e.g. testing support for ID selectors).
+
+Examples of good test assertions:
+
+* "This test checks that a background image with no intrinsic size
+   covers the entire padding box."
+* "This test checks that 'word-spacing' affects each space (U+0020)
+  and non-breaking space (U+00A0)."
+* "This test checks that if 'top' and 'bottom' offsets are specified
+  on an absolutely-positioned replaced element, then any remaining
+  space is split amongst the 'auto' vertical margins."
+* "This test checks that 'text-indent' affects only the first line
+  of a block container if that line is also the first formatted line
+  of an element."
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/css-user-styles.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/css-user-styles.md
new file mode 100644
index 0000000..9dac5af
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/css-user-styles.md
@@ -0,0 +1,90 @@
+# CSS User Stylesheets
+
+Some test may require special user style sheets to be applied in order
+for the case to be verified. In order for proper indications and
+prerequisite to be displayed every user style sheet should contain the
+following rules.
+
+``` css
+#user-stylesheet-indication
+{
+   /* Used by the harness to display an indication there is a user
+   style sheet applied */
+    display: block!important;
+}
+```
+
+The rule ```#user-stylesheet-indication``` is to be used by any
+harness running the test suite.
+
+A harness should identify test that need a user style sheet by
+looking at their flags meta tag. It then should display appropriate
+messages indicating if a style sheet is applied or if a style sheet
+should not be applied.
+
+Harness style sheet rules:
+
+``` css
+.userstyle
+{
+    color: green;
+    display: none;
+}
+.nouserstyle
+{
+    color: red;
+    display: none;
+}
+```
+
+Harness userstyle flag found:
+
+``` html
+<p id="user-stylesheet-indication" class="userstyle">A user style
+sheet is applied.</p>
+```
+
+Harness userstyle flag NOT found:
+
+``` html
+<p id="user-stylesheet-indication" class="nouserstyle">A user style
+sheet is applied.</p>
+```
+
+Within the test case it is recommended that the case itself indicate
+the necessary user style sheet that is required.
+
+Examples: (code for the [`cascade.css`][cascade-css] file)
+
+``` css
+#cascade /* ID name should match user style sheet file name */
+{
+    /* Used by the test to hide the prerequisite */
+    display: none;
+}
+```
+
+The rule ```#cascade``` in the example above is used by the test
+page to hide the prerequisite text. The rule name should match the
+user style sheet CSS file name in order to keep this orderly.
+
+Examples: (code for [the `cascade-###.xht` files][cascade-xht])
+
+``` html
+<p id="cascade">
+    PREREQUISITE: The <a href="support/cascade.css">
+    "cascade.css"</a> file is enabled as the user agent's user style
+    sheet.
+</p>
+```
+
+The id value should match the user style sheet CSS file name and the
+user style sheet rule that is used to hide this text when the style
+sheet is properly applied.
+
+Please flag test that require user style sheets with the userstyle
+flag so people running the tests know that a user style sheet is
+required.
+
+[cascade-css]: https://github.com/w3c/csswg-test/blob/master/css21/cascade/support/cascade.css
+[cascade-xht]: https://github.com/w3c/csswg-test/blob/master/css21/cascade/cascade-001.xht
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/file-names.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/file-names.md
new file mode 100644
index 0000000..57a91f0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/file-names.md
@@ -0,0 +1,68 @@
+# File Name Flags
+
+The test filename is significant in determining the type of test it
+contains, and enabling specific optional features. This page documents
+the various flags available and their meaning.
+
+
+### Test Type
+
+These flags must be the last element in the filename before the
+extension e.g. `foo-manual.html` will indicate a manual test, but
+`foo-manual-other.html` will not. Unlike test features, test types
+are mutually exclusive.
+
+
+`-manual`
+ : Indicates that a test is a non-automated test.
+
+`-visual`
+ : Indicates that a file is a visual test.
+
+
+### Test Features
+
+These flags are preceded by a `.` in the filename, and must
+themselves precede any test type flag, but are otherwise unordered.
+
+
+`.https`
+ : Indicates that a test is loaded over HTTPS.
+
+ `.h2`
+ : Indicates that a test is loaded over HTTP/2.
+
+`.sub`
+ : Indicates that a test uses the [server-side substitution][]
+   feature.
+
+`.window`
+ : (js files only) Indicates that the file generates a test in which
+    it is run in a Window environment.
+
+`.worker`
+ : (js files only) Indicates that the file generates a test in which
+    it is run in a dedicated worker environment.
+
+`.any`
+ : (js files only) Indicates that the file generates tests in which it
+    is [run in multiple scopes](testharness).
+
+`.optional`
+ : Indicates that a test makes assertions about optional behavior in a
+   specification, typically marked by the [RFC 2119] "MAY" or "OPTIONAL"
+   keywords. This flag should not be used for "SHOULD"; such requirements
+   can be tested with regular tests, like "MUST".
+
+`.tentative`
+ : Indicates that a test makes assertions not yet required by any specification,
+   or in contradiction to some specification. This is useful when implementation
+   experience is needed to inform the specification. It should be apparent in
+   context why the test is tentative and what needs to be resolved to make it
+   non-tentative.
+
+It's preferable that `.window`, `.worker`, and `.any` are immediately followed
+by their final `.js` extension.
+
+[server-side substitution]: https://wptserve.readthedocs.io/en/latest/pipes.html#sub
+[RFC 2119]: https://tools.ietf.org/html/rfc2119
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/general-guidelines.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/general-guidelines.md
new file mode 100644
index 0000000..531c9a5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/general-guidelines.md
@@ -0,0 +1,199 @@
+# General Test Guidelines
+
+### File Paths and Names
+
+When choosing where in the directory structure to put any new tests,
+try to follow the structure of existing tests for that specification;
+if there are no existing tests, it is generally recommended to create
+subdirectories for each section.
+
+Due to path length limitations on Windows, test paths must be less
+that 150 characters relative to the test root directory (this gives
+vendors just over 100 characters for their own paths when running in
+automation).
+
+File names should generally be somewhat descriptive of what is being
+tested; very generic names like `001.html` are discouraged. A common
+format is `test-topic-001.html`, where `test-topic` is a short
+identifier that describes the test. It should avoid conjunctions,
+articles, and prepositions as it should be as concise as possible. The
+integer that follows is normally just increased incrementally, and
+padded to three digits. (If you'd end up with more than 999 tests,
+your `test-topic` is probably too broad!)
+
+The test filename is significant in enabling specific optional features, such as HTTPS
+or server-side substitution. See the documentation on [file names flags][file-name-flags]
+for more details.
+
+In the css directory, the file names should be unique within the whole
+css/ directory, regardless of where they are in the directory structure.
+
+### HTTPS
+
+By default, tests are served over plain HTTP. If a test requires HTTPS
+it must be given a filename containing `.https.` e.g.,
+`test-secure.https.html`, or be the generated service worker test of a
+`.https`-less `.any` test. For more details see the documentation on
+[file names][file-name-flags].
+
+### HTTP2
+
+If a test must be served from an HTTP/2 server, it must be given a
+filename containing `.h2`.
+
+#### Support Files
+
+Various support files are available in in the directories named `/common/`,
+`/media/`, and `/css/support/`. Reusing existing resources is encouraged where
+possible, as is adding generally-useful files to these common areas rather than
+to specific test suites.
+
+
+#### Tools
+
+Sometimes you may want to add a script to the repository that's meant
+to be used from the command line, not from a browser (e.g., a script
+for generating test files). If you want to ensure (e.g., for security
+reasons) that such scripts will only be usable from the command line
+but won't be handled by the HTTP server then place them in a `tools`
+subdirectory at the appropriate level—the server will then return a
+404 if they are requested.
+
+For example, if you wanted to add a script for use with tests in the
+`notifications` directory, create the `notifications/tools`
+subdirectory and put your script there.
+
+
+### File Formats
+
+Tests are generally formatted as HTML (including XHTML) or XML (including SVG).
+Some test types support other formats:
+
+- [testharness.js tests](testharness) may be expressed as JavaScript files
+  ([the WPT server automatically generates the HTML documents for these][server
+  features])
+- [WebDriver specification tests](wdspec) are expressed as Python files
+
+The best way to determine how to format a new test is to look at how similar
+tests have been formatted. You can also ask for advice in [the project's IRC
+room][IRC].
+
+
+### Character Encoding
+
+Except when specifically testing encoding, files must be encoded in
+UTF-8. In file formats where UTF-8 is not the default encoding, they
+must contain metadata to mark them as such (e.g., `<meta
+charset=utf-8>` in HTML files) or be pure ASCII.
+
+
+### Server Side Support
+
+The custom web server
+supports [a variety of features][server features] useful for testing
+browsers, including (but not limited to!) support for writing out
+appropriate domains and custom (per-file and per-directory) HTTP
+headers.
+
+
+### Be Short
+
+Tests should be as short as possible. For reftests in particular
+scrollbars at 800&#xD7;600px window size must be avoided unless scrolling
+behavior is specifically being tested. For all tests extraneous
+elements on the page should be avoided so it is clear what is part of
+the test (for a typical testharness test, the only content on the page
+will be rendered by the harness itself).
+
+
+### Be Minimal
+
+Tests should generally avoid depending on edge case behavior of
+features that they don't explicitly intend on testing. For example,
+except where testing parsing, tests should contain
+no [parse errors](https://validator.nu).
+
+This is not, however, to discourage testing of edge cases or
+interactions between multiple features; such tests are an essential
+part of ensuring interoperability of the web platform.
+
+
+### Be Cross-Platform
+
+Tests should be as cross-platform as reasonably possible, working
+across different devices, screen resolutions, paper sizes, etc. The
+assumptions that can be relied on are documented [here][assumptions];
+tests that rely on anything else should be manual tests that document
+their assumptions.
+
+Fonts cannot be relied on to be either installed or to have specific
+metrics. As such, in most cases when a known font is needed, [Ahem][ahem]
+should be used and loaded as a web font. In other cases, `@font-face`
+should be used.
+
+
+### Be Self-Contained
+
+Tests must not depend on external network resources, including
+w3c-test.org. When these tests are run on CI systems they are
+typically configured with access to external resources disabled, so
+tests that try to access them will fail. Where tests want to use
+multiple hosts this is possible through a known set of subdomains and
+the [text substitution features of wptserve](server-features).
+
+
+### Be Self-Describing
+
+Tests should make it obvious when they pass and when they fail. It
+shouldn't be necessary to consult the specification to figure out
+whether a test has passed of failed.
+
+
+### Style Rules
+
+A number of style rules should be applied to the test file. These are
+not uniformly enforced throughout the existing tests, but will be for
+new tests. Any of these rules may be broken if the test demands it:
+
+ * No trailing whitespace
+ * Use spaces rather than tabs for indentation
+ * Use UNIX-style line endings (i.e. no CR characters at EOL)
+
+We have a lint tool for catching these and other common mistakes. You
+can run it manually by starting the `wpt` executable from the root of
+your local web-platform-tests working directory, and invoking the
+`lint` subcommand, like this:
+
+```
+./wpt lint
+```
+
+The lint tool is also run automatically for every submitted pull request,
+and reviewers will not merge branches with tests that have lint errors, so
+you must fix any errors the lint tool reports. For details on doing that,
+see the [lint-tool documentation][lint-tool].
+
+But in the unusual case of error reports for things essential to a certain
+test or that for other exceptional reasons shouldn't prevent a merge of a
+test, update and commit the `lint.whitelist` file in the web-platform-tests
+root directory to suppress the error reports. For details on doing that,
+see the [lint-tool documentation][lint-tool].
+
+
+## CSS-Specific Requirements
+
+In order to be included in an official specification test suite, tests
+for CSS have some additional requirements for:
+
+* [Metadata][css-metadata], and
+* [User style sheets][css-user-styles].
+
+
+[server features]: server-features
+[assumptions]: assumptions
+[ahem]: ahem
+[IRC]: irc://irc.w3.org:6667/testing
+[lint-tool]: lint-tool
+[css-metadata]: css-metadata
+[css-user-styles]: css-user-styles
+[file-name-flags]: file-names
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/github-intro.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/github-intro.md
new file mode 100644
index 0000000..44b6828
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/github-intro.md
@@ -0,0 +1,311 @@
+# Introduction to GitHub
+
+All the basics that you need to know are documented on this page, but for the
+full GitHub documentation, visit [help.github.com][help].
+
+If you are already an experienced Git/GitHub user, all you need to know is that
+we use the [normal GitHub Pull Request workflow][github flow] for test
+submissions.
+
+If you are a first-time GitHub user, read on for more details of the workflow.
+
+## Setup
+
+1.  Create a GitHub account if you do not already have one on
+    [github.com][github].
+
+2.  Download and install the latest version of Git:
+    [https://git-scm.com/downloads][git]; please refer to the instructions there
+    for different platforms.
+
+3.  Configure your settings so your commits are properly labeled:
+
+    On Mac or Linux or Solaris, open the Terminal.
+
+    On Windows, open Git Bash (From the Start Menu > Git > Git Bash).
+
+    At the prompt, type:
+
+        $ git config --global user.name "Your Name"
+
+    _This will be the name that is displayed with your test submissions_
+
+    Next, type:
+
+        $ git config --global user.email "your_email@address.com"
+
+    _This should be the email address you used to create the account in Step 1._
+
+4.  (Optional) If you don't want to enter your username and password every
+    time you talk to the remote server, you'll need to set up password caching.
+    See [Caching your GitHub password in Git][password-caching].
+
+## Fork the test repository
+
+Now that you have Git set up, you will need to "fork" the test repository. Your
+fork will be a completely independent version of the repository, hosted on
+GitHub.com. This will enable you to [submit](#submit) your tests using a pull
+request (more on this [below](#submit)).
+
+1.  In the browser, go to [web-platform-tests on GitHub][main-repo].
+
+2.  Click the ![fork](/assets/forkbtn.png) button in the upper right.
+
+3.  The fork will take several seconds, then you will be redirected to your
+    GitHub page for this forked repository.
+    You will now be at
+    **https://github.com/username/wpt**.
+
+4. After the fork is complete, you're ready to [clone](#clone).
+
+## Clone
+
+If your [fork](#fork) was successful, the next step is to clone (download a copy of the files).
+
+### Clone the test repository
+
+Open a command prompt in the directory where you want to keep the tests. Then
+execute the following command:
+
+    $ git clone https://github.com/username/wpt.git
+
+This will download the tests into a directory named for the repository: `wpt/`.
+
+You should now have a full copy of the test repository on your local
+machine. Feel free to browse the directories on your hard drive. You can also
+[browse them on github.com][main-repo] and see the full history of
+contributions there.
+
+## Configure Remote / Upstream
+
+Your forked repository is completely independent of the canonical repository,
+which is commonly referred to as the "upstream" repository. Synchronizing your
+forked repository with the upstream repository will keep your forked local copy
+up-to-date with the latest commits.
+
+1.  On the command line, navigate to to the directory where your forked copy of
+    the repository is located.
+
+2.  Make sure that you are on the master branch.  This will  be the case if you
+    just forked, otherwise switch to master.
+
+        $ git checkout master
+
+3.  Next, add the remote of the repository your forked.  This assigns the
+    original repository to a remote called "upstream":
+
+        $ git remote add upstream https://github.com/web-platform-tests/wpt.git
+
+4.  To pull in changes in the original repository that are not present in your
+    local repository first fetch them:
+
+        $ git fetch upstream
+
+    Then merge them into your local repository:
+
+        $ git merge upstream/master
+
+    For additional information, please see the [GitHub docs][github-fork-docs].
+
+## Configure your environment
+
+If all you intend to do is to load [manual tests](../writing-tests/manual) or [ref tests](../writing-tests/reftests) from your local file system,
+the above setup should be sufficient.
+But many tests (and in particular, all [testharness.js tests](../writing-tests/testharness)) require a local web server.
+
+See [Local Setup][local-setup] for more information.
+
+## Branch
+
+Now that you have everything locally, create a branch for your tests.
+
+_Note: If you have already been through these steps and created a branch
+and now want to create another branch, you should always do so from the
+master branch. To do this follow the steps from the beginning of the [previous
+section](#configure-remote-upstream). If you don't start with a clean master
+branch you will end up with a big nested mess._
+
+At the command line:
+
+    $ git checkout -b topic
+
+This will create a branch named `topic` and immediately
+switch this to be your active working branch.
+
+The branch name should describe specifically what you are testing. For example:
+
+    $ git checkout -b flexbox-flex-direction-prop
+
+You're ready to start writing tests! Come back to this page you're ready to
+[commit](#commit) them or [submit](#submit) them for review.
+
+
+## Commit
+
+Before you submit your tests for review and contribution to the main test
+repository, you'll need to first commit them locally, where you now have your
+own personal version control system with git. In fact, as you are writing your
+tests, you may want to save versions of your work as you go before you submit
+them to be reviewed and merged.
+
+1.  When you're ready to save a version of your work, open a command
+    prompt and change to the directory where your files are.
+
+2.  First, ask git what new or modified files you have:
+
+        $ git status
+
+    _This will show you files that have been added or modified_.
+
+3.  For all new or modified files, you need to tell git to add them to the
+    list of things you'd like to commit:
+
+        $ git add [file1] [file2] ... [fileN]
+
+    Or:
+
+        $ git add [directory_of_files]
+
+4.  Run `git status` again to see what you have on the 'Changes to be
+    committed' list. These files are now 'staged'. Alternatively, you can run
+    `git diff --staged` to see a visual representation of the changes to be
+    committed.
+
+5.  Once you've added everything, you can commit and add a message to this
+    set of changes:
+
+        $ git commit -m "Tests for indexed getters in the HTMLExampleInterface"
+
+6.  Repeat these steps as many times as you'd like before you submit.
+
+## Verify
+
+The Web Platform Test project has an automated tool
+to verify that coding conventions have been followed,
+and to catch a number of common mistakes.
+
+We recommend running this tool locally. That will help you discover and fix
+issues that would make it hard for us to accept your contribution.
+
+1. On the command line, navigate to to the directory where your clone
+of the repository is located.
+
+2. Run `./wpt lint`
+
+3. Fix any mistake it reports and [commit](#commit) again.
+
+For more details, see the [documentation about the lint tool](../writing-tests/lint-tool).
+
+## Submit
+
+If you're here now looking for more instructions, that means you've written
+some awesome tests and are ready to submit them. Congratulations and welcome
+back!
+
+1.  The first thing you do before submitting them to the web-platform-tests
+    repository is to push them back up to your fork:
+
+        $ git push origin topic
+
+    _Note: Here,_ `origin` _refers to remote repository from which you cloned
+    (downloaded) the files after you forked, referred to as
+    web-platform-tests.git in the previous example;_
+    `topic` _refers to the name of your local branch that
+    you want to share_.
+
+2.  Now you can send a message that you have changes or additions you'd like
+    to be reviewed and merged into the main (original) test repository. You do
+    this by creating a pull request. In a browser, open the GitHub page for
+    your forked repository: **https://github.com/username/wpt**.
+
+3. Now create the pull request.  There are several ways to create a PR in the
+GitHub UI.  Below is one method and others can be found on
+[GitHub.com][github-createpr]
+
+    1. Click the ![new pull request](../assets/pullrequestbtn.png) button.
+
+    2.  On the left, you should see the base repository is the
+        web-platform-tests/wpt. On the right, you should see your fork of that
+        repository. In the branch menu of your forked repository, switch to `topic`
+
+        If you see "There isn't anything to compare", make sure your fork and
+        your `topic` branch is selected on the right side.
+
+    3. Select the ![create pull request](../assets/createpr.png) button at the top.
+
+    4. Scroll down and review the summary of changes.
+
+    5. Scroll back up and in the Title field, enter a brief description for
+       your submission.
+
+       Example: "Tests for CSS Transforms skew() function."
+
+    6.  If you'd like to add more detailed comments, use the comment field
+    below.
+
+    7.  Click ![the create pull request button](../assets/createpr.png)
+
+
+4. Wait for feedback on your pull request and once your pull request is
+accepted, delete your branch (see '[When Pull Request is Accepted](#cleanup)').
+
+[This page on the submissions process](submission-process) has more detail
+about what to expect when contributing code to WPT.
+
+## Refine
+
+Once you submit your pull request, a reviewer will check your proposed changes
+for correctness and style. They may ask you to modify your code. When you are
+ready to make the changes, follow these steps:
+
+1.  Check out the branch corresponding to your changes e.g. if your branch was
+    called `topic`
+    run:
+
+        $ git checkout topic
+
+2.  Make the changes needed to address the comments, and commit them just like
+    before.
+
+3.  Push the changes to the remote branch containing the pull request:
+
+        $ git push origin topic
+
+4.  The pull request will automatically be updated with the new commit.
+
+Sometimes it takes multiple iterations through a review before the changes are
+finally accepted. Don't worry about this; it's totally normal. The goal of test
+review is to work together to create the best possible set of tests for the web
+platform.
+
+## Cleanup
+Once your pull request has been accepted, you will be notified in the GitHub
+user interface, and you may get an email. At this point, your changes have been merged
+into the main test repository. You do not need to take any further action
+on the test but you should delete your branch. This can easily be done in
+the GitHub user interface by navigating to the pull request and clicking the
+"Delete Branch" button.
+
+![pull request accepted delete branch](/assets/praccepteddelete.png)
+
+Alternatively, you can delete the branch on the command line.
+
+    $ git push origin --delete <branchName>
+
+## Further Reading
+
+Git is a very powerful tool, and there are many ways to achieve subtly
+different results. Recognizing when (and understanding how) to use other
+approaches is beyond the scope of this tutorial. [The Pro Git Book][git-book]
+is a free digital resource that can help you learn more.
+
+[local-setup]: ../running-tests/from-local-system
+[git]: https://git-scm.com/downloads
+[git-book]: https://git-scm.com/book
+[github]: https://github.com/
+[github-fork-docs]: https://help.github.com/articles/fork-a-repo
+[github-createpr]: https://help.github.com/articles/creating-a-pull-request
+[help]: https://help.github.com/
+[main-repo]: https://github.com/web-platform-tests/wpt
+[password-caching]: https://help.github.com/articles/caching-your-github-password-in-git
+[github flow]: https://guides.github.com/introduction/flow/
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/h2tests.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/h2tests.md
new file mode 100644
index 0000000..c13295e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/h2tests.md
@@ -0,0 +1,156 @@
+# Writing H2 Tests
+
+> <b>Important:</b> The HTTP/2.0 server requires you to have Python 2.7.10+
+and OpenSSL 1.0.2+. This is because HTTP/2.0 is negotiated using the
+[TLS ALPN](https://tools.ietf.org/html/rfc7301) extension, which is only supported in [OpenSSL 1.0.2](https://www.openssl.org/news/openssl-1.0.2-notes.html) and up.
+
+These instructions assume you are already familiar with the testing
+infrastructure and know how to write a standard HTTP/1.1 test.
+
+On top of the standard `main` handler that the H1 server offers, the
+H2 server also offers support for specific frame handlers in the Python
+scripts. Currently there is support for for `handle_headers` and `handle_data`.
+Unlike the `main` handler, these  are run whenever the server receives a
+HEADERS frame (RequestReceived event) or a DATA frame (DataReceived event).
+`main` can still be used, but it will be run after the server has received
+the request in its entirety.
+
+Here is what a Python script for a test might look like:
+```python
+def handle_headers(frame, request, response):
+    if request.headers["test"] == "pass":
+        response.status = 200
+        response.headers.update([('test', 'passed')])
+        response.write_status_headers()
+    else:
+        response.status = 403
+        response.headers.update([('test', 'failed')])
+        response.write_status_headers()
+        response.writer.end_stream()
+
+def handle_data(frame, request, response):
+    response.writer.write_data(frame.data[::-1])
+
+def main(request, response):
+    response.writer.write_data('\nEnd of File', last=True)
+```
+
+The above script is fairly simple:
+1. Upon receiving the HEADERS frame, `handle_headers` is run.
+    - This checks for a header called 'test' and checks if it is set to 'pass'.
+    If true, it will immediately send a response header, otherwise it responds
+    with a 403 and ends the stream.
+2. Any DATA frames received will then be handled by `handle_data`. This will
+simply reverse the data and send it back.
+3. Once the request has been fully received, `main` is run which will send
+one last DATA frame and signal its the end of the stream.
+
+## Response Writer API ##
+
+The H2Response API is pretty much the same as the H1 variant, the main API
+difference lies in the H2ResponseWriter which is accessed through `response.writer`
+
+---
+
+#### `write_headers(self, headers, status_code, status_message=None, stream_id=None, last=False):`
+Write a HEADER frame using the H2 Connection object, will only work if the
+stream is in a state to send HEADER frames. This will automatically format
+the headers so that pseudo headers are at the start of the list and correctly
+prefixed with ':'. Since this using the H2 Connection object, it requires that
+the stream is in the correct state to be sending this frame.
+
+> <b>Note</b>: Will raise ProtocolErrors if pseudo headers are missing.
+
+- <b>Parameters</b>
+
+    - <b>headers</b>: List of (header, value) tuples
+    - <b>status_code</b>: The HTTP status code of the response
+    - <b>stream_id</b>: Id of stream to send frame on. Will use the request stream ID if None
+    - <b>last</b>: Flag to signal if this is the last frame in stream.
+
+---
+
+#### `write_data(self, item, last=False, stream_id=None):`
+Write a DATA frame using the H2 Connection object, will only work if the
+stream is in a state to send DATA frames. Uses flow control to split data
+into multiple data frames if it exceeds the size that can be in a single frame.
+Since this using the H2 Connection object, it requires that the stream is in
+the correct state to be sending this frame.
+
+- <b>Parameters</b>
+
+    - <b>item</b>: The content of the DATA frame
+    - <b>last</b>: Flag to signal if this is the last frame in stream.
+    - <b>stream_id</b>: Id of stream to send frame on. Will use the request stream ID if None
+
+---
+
+#### `write_push(self, promise_headers, push_stream_id=None, status=None, response_headers=None, response_data=None):`
+This will write a push promise to the request stream. If you do not provide
+headers and data for the response, then no response will be pushed, and you
+should send them yourself using the ID returned from this function.
+
+- <b>Parameters</b>
+    - <b>promise_headers</b>: A list of header tuples that matches what the client would use to
+                        request the pushed response
+    - <b>push_stream_id</b>: The ID of the stream the response should be pushed to. If none given, will
+                       use the next available id.
+    - <b>status</b>: The status code of the response, REQUIRED if response_headers given
+    - <b>response_headers</b>: The headers of the response
+    - <b>response_data</b>: The response data.
+
+- <b>Returns</b>: The ID of the push stream
+
+---
+
+#### `write_raw_header_frame(self, headers, stream_id=None, end_stream=False, end_headers=False, frame_cls=HeadersFrame):`
+Unlike `write_headers`, this does not check to see if a stream is in the
+correct state to have HEADER frames sent through to it. It also won't force
+the order of the headers or make sure pseudo headers are prefixed with ':'.
+It will build a HEADER frame and send it without using the H2 Connection
+object other than to HPACK encode the headers.
+
+> <b>Note</b>: The `frame_cls` parameter is so that this class can be reused
+by `write_raw_continuation_frame`, as their construction is identical.
+
+- <b>Parameters</b>
+    - <b>headers</b>: List of (header, value) tuples
+    - <b>stream_id</b>: Id of stream to send frame on. Will use the request stream ID if None
+    - <b>end_stream</b>: Set to `True` to add END_STREAM flag to frame
+    - <b>end_headers</b>: Set to `True` to add END_HEADERS flag to frame
+
+---
+
+#### `write_raw_data_frame(self, data, stream_id=None, end_stream=False):`
+Unlike `write_data`, this does not check to see if a stream is in the correct
+state to have DATA frames sent through to it. It will build a DATA frame and
+send it without using the H2 Connection object. It will not perform any flow control checks.
+
+- <b>Parameters</b>
+    - <b>data</b>: The data to be sent in the frame
+    - <b>stream_id</b>: Id of stream to send frame on. Will use the request stream ID if None
+    - <b>end_stream</b>: Set to True to add END_STREAM flag to frame
+
+---
+
+#### `write_raw_continuation_frame(self, headers, stream_id=None, end_headers=False):`
+This provides the ability to create and write a CONTINUATION frame to the
+stream, which is not exposed by `write_headers` as the h2 library handles
+the split between HEADER and CONTINUATION internally. Will perform HPACK
+encoding on the headers. It also ignores the state of the stream.
+
+This calls `write_raw_data_frame` with `frame_cls=ContinuationFrame` since
+the HEADER and CONTINUATION frames are constructed in the same way.
+
+- <b>Parameters</b>:
+    - <b>headers</b>: List of (header, value) tuples
+    - <b>stream_id</b>: Id of stream to send frame on. Will use the request stream ID if None
+    - <b>end_headers</b>: Set to True to add END_HEADERS flag to frame
+
+---
+
+#### `end_stream(self, stream_id=None):`
+Ends the stream with the given ID, or the one that request was made on if no ID given.
+
+- <b>Parameters</b>
+    - <b>stream_id</b>: Id of stream to send frame on. Will use the request stream ID if None
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/idlharness.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/idlharness.md
new file mode 100644
index 0000000..13e1dc03
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/idlharness.md
@@ -0,0 +1,134 @@
+# idlharness.js API
+
+## Introduction ##
+
+`idlharness.js` automatically generates browser tests for WebIDL interfaces, using
+the testharness.js framework.  To use, first include the following:
+
+```html
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/resources/WebIDLParser.js></script>
+<script src=/resources/idlharness.js></script>
+```
+
+Then you'll need some type of IDLs.  Here's some script that can be run on a
+spec written in HTML, which will grab all the elements with `class="idl"`,
+concatenate them, and replace the body so you can copy-paste:
+
+```js
+var s = "";
+[].forEach.call(document.getElementsByClassName("idl"), function(idl) {
+  //https://www.w3.org/Bugs/Public/show_bug.cgi?id=14914
+  if (!idl.classList.contains("extract"))
+  {
+    if (s !== "")
+    {
+      s += "\n\n";
+    }
+    s += idl.textContent.replace(/ +$/mg, "");
+  }
+});
+document.body.innerHTML = '<pre></pre>';
+document.body.firstChild.textContent = s;
+```
+
+Once you have that, put it in your script somehow.  The easiest way is to
+embed it literally in an HTML file with `<script type=text/plain>` or similar,
+so that you don't have to do any escaping.  Another possibility is to put it
+in a separate .idl file that's fetched via XHR or similar.  Sample usage:
+
+```js
+var idl_array = new IdlArray();
+idl_array.add_untested_idls("interface Node { readonly attribute DOMString nodeName; };");
+idl_array.add_idls("interface Document : Node { readonly attribute DOMString URL; };");
+idl_array.add_objects({Document: ["document"]});
+idl_array.test();
+```
+
+This tests that `window.Document` exists and meets all the requirements of
+WebIDL.  It also tests that window.document (the result of evaluating the
+string "document") has URL and nodeName properties that behave as they
+should, and otherwise meets WebIDL's requirements for an object whose
+primary interface is Document.  It does not test that window.Node exists,
+which is what you want if the Node interface is already tested in some other
+specification's suite and your specification only extends or refers to it.
+Of course, each IDL string can define many different things, and calls to
+add_objects() can register many different objects for different interfaces:
+this is a very simple example.
+
+## Public methods of IdlArray ##
+
+IdlArray objects can be obtained with `new IdlArray()`.  Anything not
+documented in this section should be considered an implementation detail,
+and outside callers should not use it.
+
+### `add_idls(idl_string)`
+  Parses `idl_string` (throwing on parse error) and adds the results to the
+  IdlArray.  All the definitions will be tested when you run test().  If
+  some of the definitions refer to other definitions, those must be present
+  too.  For instance, if `idl_string` says that `Document` inherits from `Node`,
+  the `Node` interface must also have been provided in some call to `add_idls()`
+  or `add_untested_idls()`.
+
+### `add_untested_idls(idl_string)`
+  Like `add_idls()`, but the definitions will not be tested.  If an untested
+  interface is added and then extended with a tested partial interface, the
+  members of the partial interface will still be tested.  Also, all the
+  members will still be tested for objects added with `add_objects()`, because
+  you probably want to test that (for instance) window.document has all the
+  properties from `Node`, not just `Document`, even if the `Node` interface itself
+  is tested in a different test suite.
+
+### `add_objects(dict)`
+  `dict` should be an object whose keys are the names of interfaces or
+  exceptions, and whose values are arrays of strings.  When an interface or
+  exception is tested, every string registered for it with `add_objects()`
+  will be evaluated, and tests will be run on the result to verify that it
+  correctly implements that interface or exception.  This is the only way to
+  test anything about `[NoInterfaceObject]` interfaces, and there are many
+  tests that can't be run on any interface without an object to fiddle with.
+
+  The interface has to be the *primary* interface of all the objects
+  provided.  For example, don't pass `{Node: ["document"]}`, but rather
+  `{Document: ["document"]}`.  Assuming the `Document` interface was declared to
+  inherit from `Node`, this will automatically test that document implements
+  the `Node` interface too.
+
+  Warning: methods will be called on any provided objects, in a manner that
+  WebIDL requires be safe.  For instance, if a method has mandatory
+  arguments, the test suite will try calling it with too few arguments to
+  see if it throws an exception.  If an implementation incorrectly runs the
+  function instead of throwing, this might have side effects, possibly even
+  preventing the test suite from running correctly.
+
+### `prevent_multiple_testing(name)`
+  This is a niche method for use in case you're testing many objects that
+  implement the same interfaces, and don't want to retest the same
+  interfaces every single time.  For instance, HTML defines many interfaces
+  that all inherit from `HTMLElement`, so the HTML test suite has something
+  like
+
+```js
+.add_objects({
+  HTMLHtmlElement: ['document.documentElement'],
+  HTMLHeadElement: ['document.head'],
+  HTMLBodyElement: ['document.body'],
+  ...
+})
+```
+
+  and so on for dozens of element types.  This would mean that it would
+  retest that each and every one of those elements implements `HTMLElement`,
+  `Element`, and `Node`, which would be thousands of basically redundant tests.
+  The test suite therefore calls `prevent_multiple_testing("HTMLElement")`.
+  This means that once one object has been tested to implement `HTMLElement`
+  and its ancestors, no other object will be.  Thus in the example code
+  above, the harness would test that `document.documentElement` correctly
+  implements `HTMLHtmlElement`, `HTMLElement`, `Element`, and `Node`; but
+  `document.head` would only be tested for `HTMLHeadElement`, and so on for
+  further objects.
+
+### `test()`
+  Run all tests.  This should be called after you've called all other
+  methods to add IDLs and objects.
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/index.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/index.md
new file mode 100644
index 0000000..90a67c21
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/index.md
@@ -0,0 +1,96 @@
+# Writing Tests
+
+So you'd like to write new tests for WPT? Great! For starters, we recommend
+reading [the introduction](../index) to learn how the tests are organized and
+interpreted. You might already have an idea about what needs testing, but it's
+okay if you don't know where to begin. In either case, [the guide on making a
+testing plan](making-a-testing-plan) will help you decide what to write.
+
+There's also a load of [general guidelines](general-guidelines) that apply to all tests.
+
+```eval_rst
+.. toctree::
+   :maxdepth: 1
+
+   general-guidelines
+   ahem
+   assumptions
+   crashtest
+   css-metadata
+   css-user-styles
+   file-names
+   h2tests
+   lint-tool
+   making-a-testing-plan
+   manual
+   reftest-tutorial
+   reftests
+   print-reftests
+   rendering
+   server-features
+   submission-process
+   testdriver
+   testdriver-extension-tutorial
+   testharness
+   testharness-tutorial
+   tools
+   visual
+   wdspec
+   test-templates
+   github-intro
+```
+
+## Test Type
+
+Tests in this project use a few different approaches to verify expected
+behavior. The tests can be classified based on the way they express
+expectations:
+
+* Rendering tests should be used to verify that the browser graphically
+  displays pages as expected. See the [rendering test guidelines](rendering)
+  for tips on how to write great rendering tests. There are a few different
+  ways to write rendering tests:
+
+  * [Reftests](reftests) should be used to test rendering and layout. They
+    consist of two or more pages with assertions as to whether they render
+    identically or not.
+
+  * [Visual tests](visual) should be used for checking rendering where there is
+    a large number of conforming renderings such that reftests are impractical.
+    They consist of a page that renders to final state at which point a
+    screenshot can be taken and compared to an expected rendering for that user
+    agent on that platform.
+
+* [testharness.js](testharness) tests should be used (where possible!) for
+  testing everything else. They are built with the testharness.js unit testing
+  framework, and consist of assertions written in JavaScript.
+
+* [Crashtests](crashtest) tests are used to check that the browser is
+  able to load a given document without crashing or experiencing other
+  low-level issues (asserts, leaks, etc.). They pass if the load
+  completes without error.
+
+* [wdspec](wdspec) tests are written in Python using
+  [pytest](https://docs.pytest.org/en/latest/) and test [the WebDriver browser
+  automation protocol](https://w3c.github.io/webdriver/)
+
+* [Manual tests](manual) are used as a last resort for anything that can't be
+  tested using any of the above. They consist of a page that needs manual
+  interaction or verification of the final result.
+
+In general, there is a strong preference towards reftests and testharness.js
+tests types (as they can be easily run without human interaction), so they
+should be used in preference to the others even if it results in a
+somewhat cumbersome test; there is a far weaker preference between the
+two test types, and it is at times advisable to use testharness.js tests
+for things which would typically be tested using reftests but for
+which it would be overly cumbersome.
+
+See [file names](file-names) for test types and features determined by the file names,
+and [server features](server-features) for advanced testing features.
+
+## Submitting Tests
+
+Once you've written tests, please submit them using
+the [typical GitHub Pull Request workflow](submission-process); please
+make sure you run the [`lint` script](lint-tool) before opening a pull request!
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/lint-tool.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/lint-tool.md
new file mode 100644
index 0000000..f9caca35
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/lint-tool.md
@@ -0,0 +1,82 @@
+# Lint Tool
+
+We have a lint tool for catching common mistakes in test files. You can run
+it manually by running the `wpt lint` command from the root of your local
+web-platform-tests working directory like this:
+
+```
+./wpt lint
+```
+
+The lint tool is also run automatically for every submitted pull request,
+and reviewers will not merge branches with tests that have lint errors, so
+you must either [fix all lint errors](#fixing-lint-errors), or you must
+[whitelist test files](#updating-the-whitelist) to suppress the errors.
+
+## Fixing lint errors
+
+You must fix any errors the lint tool reports, unless an error is for
+something essential to a certain test or that for some other
+exceptional reason shouldn't prevent the test from being merged; in
+those cases you can [whitelist test files](#updating-the-whitelist)
+to suppress the errors. In all other cases, follow the instructions
+below to fix all errors reported.
+
+<!--
+  This listing is automatically generated from the linting tool's Python source
+  code.
+-->
+
+```eval_rst
+.. wpt-lint-rules:: tools.lint.rules
+```
+
+## Updating the whitelist
+
+Normally you must [fix all lint errors](#fixing-lint-errors). But in the
+unusual case of error reports for things essential to certain tests or that
+for other exceptional reasons shouldn't prevent a merge of a test, you can
+update and commit the `lint.whitelist` file in the web-platform-tests root
+directory to suppress errors the lint tool would report for a test file.
+
+To add a test file or directory to the whitelist, use the following format:
+
+```
+ERROR TYPE:file/name/pattern
+```
+
+For example, to whitelist the file `example/file.html` such that all
+`TRAILING WHITESPACE` errors the lint tool would report for it are
+suppressed, add the following line to the `lint.whitelist` file:
+
+```
+TRAILING WHITESPACE:example/file.html
+```
+
+To whitelist an entire directory rather than just one file, use the `*`
+wildcard. For example, to whitelist the `example` directory such that all
+`TRAILING WHITESPACE` errors the lint tool would report for any files in it
+are suppressed, add the following line to the `lint.whitelist` file:
+
+```
+TRAILING WHITESPACE:example/*
+```
+
+Similarly, you can also
+use
+[shell-style wildcards](https://docs.python.org/2/library/fnmatch.html) to
+express other filename patterns or directory-name patterns.
+
+Finally, to whitelist just one line in a file, use the following format:
+
+```
+ERROR TYPE:file/name/pattern:line_number
+```
+
+For example, to whitelist just line 128 of the file `example/file.html`
+such that any `TRAILING WHITESPACE` error the lint tool would report for
+that line is suppressed, add the following to the `lint.whitelist` file:
+
+```
+TRAILING WHITESPACE:example/file.html:128
+```
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/making-a-testing-plan.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/making-a-testing-plan.md
new file mode 100644
index 0000000..520c5a32
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/making-a-testing-plan.md
@@ -0,0 +1,539 @@
+# Making a Testing Plan
+
+When contributing to a project as large and open-ended as WPT, it's easy to get
+lost in the details. It can be helpful to start by making a rough list of tests
+you intend to write. That plan will let you anticipate how much work will be
+involved, and it will help you stay focused once you begin.
+
+Many people come to WPT with a general testing goal in mind:
+
+- specification authors often want to test for new spec text
+- browser maintainers often want to test new features or fixes to existing
+  features
+- web developers often want to test discrepancies between browsers on their web
+  applications
+
+(If you don't have any particular goal, we can help you get started. Check out
+[the issues labeled with `type:missing-coverage` on
+GitHub.com](https://github.com/web-platform-tests/wpt/labels/type%3Amissing-coverage).
+Leave a comment if you'd like to get started with one, and don't hesitate to
+ask clarifying questions!)
+
+This guide will help you write a testing plan by:
+
+1. showing you how to use the specifications to learn what kinds of tests will
+   be most helpful
+2. developing your sense for what *doesn't* need to be tested
+3. demonstrating methods for figuring out which tests (if any) have already
+   been written for WPT
+
+The level of detail in useful testing plans can vary widely. From [a list of
+specific
+cases](https://github.com/web-platform-tests/wpt/issues/6980#issue-252255894),
+to [an outline of important coverage
+areas](https://github.com/web-platform-tests/wpt/issues/18549#issuecomment-522631537),
+to [an annotated version of the specification under
+test](https://rwaldron.github.io/webrtc-pc/), the appropriate fidelity depends
+on your needs, so you can be as precise as you feel is helpful.
+
+## Understanding the "testing surface"
+
+Web platform specifications are instructions about how a feature should work.
+They're critical for implementers to "build the right thing," but they are also
+important for anyone writing tests. We can use the same instructions to infer
+what kinds of tests would be likely to detect mistakes. Here are a few common
+patterns in specification text and the kind of tests they suggest.
+
+### Input sources
+
+Algorithms may accept input from many sources. Modifying the input is the most
+direct way we can influence the browser's behavior and verify that it matches
+the specifications. That's why it's helpful to be able to recognize different
+sources of input.
+
+```eval_rst
+================ ==============================================================
+Type of feature  Potential input sources
+================ ==============================================================
+JavaScript       parameters, `context object <https://dom.spec.whatwg.org/#context-object>`_
+HTML             element content, attributes, attribute values
+CSS              selector strings, property values, markup
+================ ==============================================================
+```
+
+Determine which input sources are relevant for your chosen feature, and build a
+list of values which seem worthwhile to test (keep reading for advice on
+identifying worthwhile values). For features that accept multiple sources of
+input, remember that the interaction between values can often produce
+interesting results. Every value you identify should go into your testing plan.
+
+*Example:* This is the first step of the `Notification` constructor from [the
+Notifications standard](https://notifications.spec.whatwg.org/#constructors):
+
+> The Notification(title, options) constructor, when invoked, must run these steps:
+>
+> 1. If the [current global
+>    object](https://html.spec.whatwg.org/multipage/webappapis.html#current-global-object)
+>    is a
+>    [ServiceWorkerGlobalScope](https://w3c.github.io/ServiceWorker/#serviceworkerglobalscope)
+>    object, then [throw](https://heycam.github.io/webidl/#dfn-throw) a
+>    `TypeError` exception.
+> 2. Let *notification* be the result of [creating a
+>    notification](https://notifications.spec.whatwg.org/#create-a-notification)
+>    given *title* and *options*. Rethrow any exceptions.
+>
+> [...]
+
+A thorough test suite for this constructor will include tests for the behavior
+of many different values of the *title* parameter and the *options* parameter.
+Choosing those values can be a challenge unto itself--see [Avoid Excessive
+Breadth](#avoid-excessive-breadth) for advice.
+
+### Browser state
+
+The state of the browser may also influence algorithm behavior. Examples
+include the current document, the dimensions of the viewport, and the entries
+in the browsing history. Just like with direct input, a thorough set of tests
+will likely need to control these values. Browser state is often more expensive
+to manipulate (whether in terms of code, execution time, or system resources),
+and you may want to design your tests to mitigate these costs (e.g. by writing
+many subtests from the same state).
+
+You may not be able to control all relevant aspects of the browser's state.
+[The `type:untestable`
+label](https://github.com/web-platform-tests/wpt/issues?q=is%3Aopen+is%3Aissue+label%3Atype%3Auntestable)
+includes issues for web platform features which cannot be controlled in a
+cross-browser way. You should include tests like these in your plan both to
+communicate your intention and to remind you when/if testing solutions become
+available.
+
+*Example:* In [the `Notification` constructor referenced
+above](https://notifications.spec.whatwg.org/#constructors), the type of "the
+current global object" is also a form of input. The test suite should include
+tests which execute with different types of global objects.
+
+### Branches
+
+When an algorithm branches based on some condition, that's an indication of an
+interesting behavior that might be missed. Your testing plan should have at
+least one test that verifies the behavior when the branch is taken and at least
+one more test that verifies the behavior when the branch is *not* taken.
+
+*Example:* The following algorithm from [the HTML
+standard](https://html.spec.whatwg.org/) describes how the
+`localStorage.getItem` method works:
+
+> The `getItem`(*key*) method must return the current value associated with the
+> given *key*. If the given *key* does not exist in the list associated with
+> the object then this method must return null.
+
+This algorithm exhibits different behavior depending on whether or not an item
+exists at the provided key. To test this thoroughly, we would write two tests:
+one test would verify that `null` is returned when there is no item at the
+provided key, and the other test would verify that an item we previously stored
+was correctly retrieved when we called the method with its name.
+
+### Sequence
+
+Even without branching, the interplay between sequential algorithm steps can
+suggest interesting test cases. If two steps have observable side-effects, then
+it can be useful to verify they happen in the correct order.
+
+Most of the time, step sequence is implicit in the nature of the
+algorithm--each step operates on the result of the step that precedes it, so
+verifying the end result implicitly verifies the sequence of the steps. But
+sometimes, the order of two steps isn't particularly relevant to the result of
+the overall algorithm. This makes it easier for implementations to diverge.
+
+There are many common patterns where step sequence is observable but not
+necessarily inherent to the correctness of the algorithm:
+
+- input validation (when an algorithm verifies that two or more input values
+  satisfy some criteria)
+- event dispatch (when an algorithm
+  [fires](https://dom.spec.whatwg.org/#concept-event-fire) two or more events)
+- object property access (when an algorithm retrieves two or more property
+  values from an object provided as input)
+
+*Example:* The following text is an abbreviated excerpt of the algorithm that
+runs during drag operations (from [the HTML
+specification](https://html.spec.whatwg.org/multipage/dnd.html#dnd)):
+
+> [...]
+> 4. Otherwise, if the user ended the drag-and-drop operation (e.g. by
+>    releasing the mouse button in a mouse-driven drag-and-drop interface), or
+>    if the `drag` event was canceled, then this will be the last iteration.
+>    Run the following steps, then stop the drag-and-drop operation:
+>    1. If the [current drag
+>       operation](https://html.spec.whatwg.org/multipage/dnd.html#current-drag-operation)
+>       is "`none`" (no drag operation) [...] Otherwise, the drag operation
+>       might be a success; run these substeps:
+>       1. Let *dropped* be true.
+>       2. If the [current target
+>          element](https://html.spec.whatwg.org/multipage/dnd.html#current-target-element)
+>          is a DOM element, [fire a DND
+>          event](https://html.spec.whatwg.org/multipage/dnd.html#fire-a-dnd-event)
+>          named `drop` at it; otherwise, use platform-specific conventions for
+>          indicating a drop.
+>       3. [...]
+>    2. [Fire a DND
+>       event](https://html.spec.whatwg.org/multipage/dnd.html#fire-a-dnd-event)
+>       named `dragend` at the [source
+>       node](https://html.spec.whatwg.org/multipage/dnd.html#source-node).
+>    3. [...]
+
+A thorough test suite will verify that the `drop` event is fired as specified,
+and it will also verify that the `dragend` event is fired as specified. An even
+better test suite will also verify that the `drop` event is fired *before* the
+`dragend` event.
+
+In September of 2019, [Chromium accidentally changed the ordering of the `drop`
+and `dragend`
+events](https://bugs.chromium.org/p/chromium/issues/detail?id=1005747), and as
+a result, real web applications stopped functioning. If there had been a test
+for the sequence of these events, then this confusion would have been avoided.
+
+When making your testing plan, be sure to look carefully for event dispatch and
+the other patterns listed above. They won't always be as clear as the "drag"
+example!
+
+### Optional behavior
+
+Specifications occasionally allow browsers discretion in how they implement
+certain features. These are described using [RFC
+2119](https://tools.ietf.org/html/rfc2119) terms like "MAY" and "OPTIONAL".
+Although browsers should not be penalized for deciding not to implement such
+behavior, WPT offers tests that verify the correctness of the browsers which
+do. Be sure to [label the test as optional according to WPT's
+conventions](file-names) so that people reviewing test results know how to
+interpret failures.
+
+*Example:* The algorithm underpinning
+[`document.getElementsByTagName`](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByTagName)
+includes the following paragraph:
+
+> When invoked with the same argument, and as long as *root*'s [node
+> document](https://dom.spec.whatwg.org/#concept-node-document)'s
+> [type](https://dom.spec.whatwg.org/#concept-document-type) has not changed,
+> the same [HTMLCollection](https://dom.spec.whatwg.org/#htmlcollection) object
+> may be returned as returned by an earlier call.
+
+That statement uses the word "may," so even though it modifies the behavior of
+the preceding algorithm, it is strictly optional. The test we write for this
+should be designated accordingly.
+
+It's important to read these sections carefully because the distinction between
+"mandatory" behavior and "optional" behavior can be nuanced. In this case, the
+optional behavior is never allowed if the document's type has changed. That
+makes for a mandatory test, one that verifies browsers don't return the same
+result when the document's type changes.
+
+## Exercising Restraint
+
+When writing conformance tests, choosing what *not* to test is sometimes just
+as hard as finding what needs testing.
+
+### Don't dive too deep
+
+Algorithms are composed of many other algorithms which themselves are defined
+in terms of still more algorithms. It can be intimidating to consider
+exhaustively testing one of those "nested" algorithms, especially when they are
+shared by many different APIs.
+
+In general, you should plan to write "surface tests" for the nested algorithms.
+That means only verifying that they exhibit the basic behavior you are
+expecting.
+
+It's definitely important to test exhaustively, but it's just as important to
+do so in a structured way. Reach out to the test suite's maintainers to learn
+if and how they have already tested those algorithms. In many cases, it's
+acceptable to test them in just one place (and maybe through a different API
+entirely), and rely only on surface-level testing everywhere else. While it's
+always possible for more tests to uncover new bugs, the chances may be slim.
+The time we spend writing tests is highly valuable, so we have to be efficient!
+
+*Example:* The following algorithm from [the DOM
+standard](https://dom.spec.whatwg.org/) powers
+[`document.querySelector`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector):
+
+> To **scope-match a selectors string** *selectors* against a *node*, run these
+> steps:
+>
+> 1. Let *s* be the result of [parse a
+>    selector](https://drafts.csswg.org/selectors-4/#parse-a-selector)
+>    *selectors*.
+> 2. If *s* is failure, then
+>    [throw](https://heycam.github.io/webidl/#dfn-throw) a
+>    "[`SyntaxError`](https://heycam.github.io/webidl/#syntaxerror)"
+>    [DOMException](https://heycam.github.io/webidl/#idl-DOMException).
+> 3. Return the result of [match a selector against a
+>    tree](https://drafts.csswg.org/selectors-4/#match-a-selector-against-a-tree)
+>    with *s* and *node*'s
+>    [root](https://dom.spec.whatwg.org/#concept-tree-root) using [scoping
+>    root](https://drafts.csswg.org/selectors-4/#scoping-root) *node*.
+
+As described earlier in this guide, we'd certainly want to test the branch
+regarding the parsing failure. However, there are many ways a string might fail
+to parse--should we verify them all in the tests for `document.querySelector`?
+What about `document.querySelectorAll`? Should we test them all there, too?
+
+The answers depend on the current state of the test suite: whether or not tests
+for selector parsing exist and where they are located. That's why it's best to
+confer with the people who are maintaining the tests.
+
+### Avoid excessive breadth
+
+When the set of input values is finite, it can be tempting to test them all
+exhaustively. When the set is very large, test authors can reduce repetition by
+defining tests programmatically in loops.
+
+Using advanced control flow techniques to dynamically generate tests can
+actually *reduce* test quality. It may obscure the intent of the tests since
+readers have to mentally "unwind" the iteration to determine what is actually
+being verified. The practice is more susceptible to bugs. These bugs may not be
+obvious--they may not cause failures, and they may exercise fewer cases than
+intended. Finally, tests authored using this approach often take a relatively
+long time to complete, and that puts a burden on people who collect test
+results in large numbers.
+
+The severity of these drawbacks varies with the complexity of the generation
+logic. For example, it would be pronounced in a test which conditionally made
+different assertions within many nested loops. Conversely, the severity would
+be low in a test which only iterated over a list of values in order to make the
+same assertions about each. Recognizing when the benefits outweigh the risks
+requires discretion, so once you understand them, you should use your best
+judgement.
+
+*Example:* We can see this consideration in the very first step of the
+`Response` constructor from [the Fetch
+standard](https://fetch.spec.whatwg.org/)
+
+> The `Response`(*body*, *init*) constructor, when invoked, must run these
+> steps:
+>
+> 1. If *init*["`status`"] is not in the range `200` to `599`, inclusive, then
+>    [throw](https://heycam.github.io/webidl/#dfn-throw) a `RangeError`.
+>
+> [...]
+
+This function accepts exactly 400 values for the "status." With [WPT's
+testharness.js](./testharness), it's easy to dynamically create one test for
+each value. Unless we have reason to believe that a browser may exhibit
+drastically different behavior for any of those values (e.g. correctly
+accepting `546` but incorrectly rejecting `547`), then the complexity of
+testing those cases probably isn't warranted.
+
+Instead, focus on writing declarative tests for specific values which are novel
+in the context of the algorithm. For ranges like in this example, testing the
+boundaries is a good idea. `200` and `599` should not produce an error while
+`199` and `600` should produce an error. Feel free to use what you know about
+the feature to choose additional values. In this case, HTTP response status
+codes are classified by the "hundred" order of magnitude, so we might also want
+to test a "3xx" value and a "4xx" value.
+
+## Assessing coverage
+
+It's very likely that WPT already has some tests for the feature (or at least
+the specification) that you're interesting in testing. In that case, you'll
+have to learn what's already been done before starting to write new tests.
+Understanding the design of existing tests will let you avoid duplicating
+effort, and it will also help you integrate your work more logically.
+
+Even if the feature you're testing does *not* have any tests, you should still
+keep these guidelines in mind. Sooner or later, someone else will want to
+extend your work, so you ought to give them a good starting point!
+
+### File names
+
+The names of existing files and folders in the repository can help you find
+tests that are relevant to your work. [This page on the design of
+WPT](../test-suite-design) goes into detail about how files are generally laid
+out in the repository.
+
+Generally speaking, every conformance tests is stored in a subdirectory
+dedicated to the specification it verifies. The structure of these
+subdirectories vary. Some organize tests in directories related to algorithms
+or behaviors. Others have a more "flat" layout, where all tests are listed
+together.
+
+Whatever the case, test authors try to choose names that communicate the
+behavior under test, so you can use them to make an educated guess about where
+your tests should go.
+
+*Example:* Imagine you wanted to write a test to verify that headers were made
+immutable by the `Request.error` method defined in [the Fetch
+standard](https://fetch.spec.whatwg.org). Here's the algorithm:
+
+> The static error() method, when invoked, must run these steps:
+>
+> 1. Let *r* be a new [Response](https://fetch.spec.whatwg.org/#response)
+>    object, whose
+>    [response](https://fetch.spec.whatwg.org/#concept-response-response) is a
+>    new [network error](https://fetch.spec.whatwg.org/#concept-network-error).
+> 2. Set *r*'s [headers](https://fetch.spec.whatwg.org/#response-headers) to a
+>    new [Headers](https://fetch.spec.whatwg.org/#headers) object whose
+>    [guard](https://fetch.spec.whatwg.org/#concept-headers-guard) is
+>    "`immutable`".
+> 3. Return *r*.
+
+In order to figure out where to write the test (and whether it's needed at
+all), you can review the contents of the `fetch/` directory in WPT. Here's how
+that looks on a UNIX-like command line:
+
+    $ ls fetch
+    api/                           data-urls/   range/
+    content-encoding/              http-cache/  README.md
+    content-length/                images/      redirect-navigate/
+    content-type/                  metadata/    security/
+    corb/                          META.yml     stale-while-revalidate/
+    cors-rfc1918/                  nosniff/
+    cross-origin-resource-policy/  origin/
+
+This test is for a behavior directly exposed through the API, so we should look
+in the `api/` directory:
+
+    $ ls fetch/api
+    abort/  cors/         headers/           policies/  request/    response/
+    basic/  credentials/  idlharness.any.js  redirect/  resources/
+
+And since this is a static method on the `Response` constructor, we would
+expect the test to belong in the `response/` directory:
+
+    $ ls fetch/api/response
+    multi-globals/                   response-static-error.html
+    response-cancel-stream.html      response-static-redirect.html
+    response-clone.html              response-stream-disturbed-1.html
+    response-consume-empty.html      response-stream-disturbed-2.html
+    response-consume.html            response-stream-disturbed-3.html
+    response-consume-stream.html     response-stream-disturbed-4.html
+    response-error-from-stream.html  response-stream-disturbed-5.html
+    response-error.html              response-stream-disturbed-6.html
+    response-from-stream.any.js      response-stream-with-broken-then.any.js
+    response-init-001.html           response-trailer.html
+    response-init-002.html
+
+There seems to be a test file for the `error` method:
+`response-static-error.html`. We can open that to decide if the behavior is
+already covered. If not, then we know where to [write the
+test](https://github.com/web-platform-tests/wpt/pull/19601)!
+
+### Failures on wpt.fyi
+
+There are many behaviors that are difficult to describe in a succinct file
+name. That's commonly the case with low-level rendering details of CSS
+specifications. Test authors may resort to generic number-based naming schemes
+for their files, e.g. `feature-001.html`, `feature-002.html`, etc. This makes
+it difficult to determine if a test case exists judging only by the names of
+files.
+
+If the behavior you want to test is demonstrated by some browsers but not by
+others, you may be able to use the *results* of the tests to locate the
+relevant test.
+
+[wpt.fyi](https://wpt.fyi) is a website which publishes results of WPT in
+various browsers. Because most browsers pass most tests, the pass/fail
+characteristics of the behavior you're testing can help you filter through a
+large number of highly similar tests.
+
+*Example:* Imagine you've found a bug in the way Safari renders the top CSS
+border of HTML tables. By searching through directory names and file names,
+you've determined the probable location for the test: the `css/CSS2/borders/`
+directory. However, there are *three hundred* files that begin with
+`border-top-`! None of the names mention the `<table>` element, so any one of
+the files may already be testing the case you found.
+
+Luckily, you also know that Firefox and Chrome do not exhibit this bug. You
+could find such tests by visual inspection of the [wpt.fyi](https://wpt.fyi)
+results overview, but [the website's "search" feature includes operators that
+let you query for this information
+directly](https://github.com/web-platform-tests/wpt.fyi/blob/master/api/query/README.md).
+To find the tests which begin with `border-top-`, pass in Chrome, pass in
+Firefox, and fail in Safari, you could write [`border-top- chrome:pass
+firefox:pass
+safari:fail](https://wpt.fyi/results/?label=master&label=experimental&aligned&q=border-top-%20safari%3Afail%20firefox%3Apass%20chrome%3Apass).
+The results show only three such tests exist:
+
+- `border-top-applies-to-005.xht`
+- `border-top-color-applies-to-005.xht`
+- `border-top-width-applies-to-005.xht`
+
+These may not describe the behavior you're interested in testing; the only way
+to know for sure is to review their contents. However, this is a much more
+manageable set to work with!
+
+### Querying file contents
+
+Some web platform features are enabled with a predictable pattern. For example,
+HTML attributes follow a fairly consistent format. If you're interested in
+testing a feature like this, you may be able to learn where your tests belong
+by querying the contents of the files in WPT.
+
+You may be able to perform such a search on the web. WPT is hosted on
+GitHub.com, and [GitHub offers some basic functionality for querying
+code](https://help.github.com/en/articles/about-searching-on-github). If your
+search criteria are short and distinctive (e.g. all files containing
+"querySelectorAll"), then this interface may be sufficient. However, more
+complicated criteria may require [regular
+expressions](https://www.regular-expressions.info/). For that, you can
+[download the WPT
+repository](https://web-platform-tests.org/writing-tests/github-intro.html) and
+use [git](https://git-scm.com) to perform more powerful searches.
+
+The following table lists some common search criteria and examples of how they
+can be expressed using regular expressions:
+
+<div class="table-container">
+
+```eval_rst
+================================= ================== ==========================
+Criteria                          Example match      Example regular expression
+================================= ================== ==========================
+JavaScript identifier references  ``obj.foo()``      ``\bfoo\b``
+JavaScript string literals        ``x = "foo";``     ``(["'])foo\1``
+HTML tag names                    ``<foo attr>``     ``<foo(\s|>|$)``
+HTML attributes                   ``<div foo=3>``    ``<[a-zA-Z][^>]*\sfoo(\s|>|=|$)``
+CSS property name                 ``style="foo: 4"`` ``([{;=\"']|\s|^)foo\s+:``
+================================= ================== ==========================
+```
+
+</div>
+
+Bear in mind that searches like this are not necessarily exhaustive. Depending
+on the feature, it may be difficult (or even impossible) to write a query that
+correctly identifies all relevant tests. This strategy can give a helpful
+guide, but the results may not be conclusive.
+
+*Example:* Imagine you're interested in testing how the `src` attribute of the
+`iframe` element works with `javascript:` URLs. Judging only from the names of
+directories, you've found a lot of potential locations for such a test. You
+also know many tests use `javascript:` URLs without describing that in their
+name. How can you find where to contribute new tests?
+
+You can design a regular expression that matches many cases where a
+`javascript:` URL is assigned to the `src` property in HTML. You can use the
+`git grep` command to query the contents of the `html/` directory:
+
+    $ git grep -lE "src\s*=\s*[\"']?javascript:" html
+    html/browsers/browsing-the-web/navigating-across-documents/javascript-url-query-fragment-components.html
+    html/browsers/browsing-the-web/navigating-across-documents/javascript-url-return-value-handling.html
+    html/dom/documents/dom-tree-accessors/Document.currentScript.html
+    html/dom/self-origin.sub.html
+    html/editing/dnd/target-origin/114-manual.html
+    html/semantics/embedded-content/media-elements/track/track-element/cloneNode.html
+    html/semantics/scripting-1/the-script-element/execution-timing/040.html
+    html/semantics/scripting-1/the-script-element/execution-timing/080.html
+    html/semantics/scripting-1/the-script-element/execution-timing/108.html
+    html/semantics/scripting-1/the-script-element/execution-timing/109.html
+    html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document-open-cancels-javascript-url-navigation.html
+
+You will still have to review the contents to know which are relevant for your
+purposes (if any), but compared to the 5,000 files in the `html/` directory,
+this list is far more approachable!
+
+## Writing the Tests
+
+With a complete testing plan in hand, you now have a good idea of the scope of
+your work. It's finally time to write the tests! There's a lot to say about how
+this is done technically. To learn more, check out [the WPT "reftest"
+tutorial](./reftest-tutorial) and [the testharness.js
+tutorial](./testharness-tutorial).
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/manual.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/manual.md
new file mode 100644
index 0000000..122a22b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/manual.md
@@ -0,0 +1,77 @@
+# Manual Tests
+
+Some testing scenarios are intrinsically difficult to automate and
+require a human to run the test and check the pass condition.
+
+## When to Write Manual Tests
+
+Whenever possible it's best to write a fully automated test. For a
+browser vendor it's possible to run an automated test hundreds of
+times a day, but manual tests are likely to be run at most a handful
+of times a year (and quite possibly approximately never!). This makes
+them significantly less useful for catching regressions than automated
+tests.
+
+However, there are certain scenarios in which this is not yet
+possible. For example:
+
+* Test which require observing animation (e.g., a test for CSS
+  animation or for video playback),
+
+* Tests that require interaction with browser security UI (e.g., a
+  test in which a user refuses a geolocation permissions grant),
+
+* Tests that require interaction with the underlying OS (e.g., tests
+  for drag and drop from the desktop onto the browser),
+
+* Tests that require non-default browser configuration (e.g., images
+  disabled), and
+
+* Tests that require interaction with the physical environment (e.g.,
+  tests that the vibration API causes the device to vibrate or that
+  various sensor APIs respond in the expected way).
+
+## Requirements for a Manual Test
+
+Manual tests are distinguished by their filename; all manual tests
+have filenames of the form `name-manual.ext` (i.e., a `-manual` suffix
+after the main filename but before the extension).
+
+Manual tests must be
+fully
+[self-describing](general-guidelines).
+It is particularly important for these tests that it is easy to
+determine the result from the information provided in the page to the
+tester, because a tester may have hundreds of tests to get through and
+little understanding of the features that they are testing. As a
+result, minimalism is especially a virtue for manual tests.
+
+A test should have, at a minimum step-by-step instructions for
+performing the test, and a clear statement of either the test result
+if it can be automatically determined after some setup or how to
+otherwise determine the outcome.
+
+Any information other than this (e.g., quotes from the spec) should be
+avoided (though, as always, can be provided in
+HTML/CSS/JS/etc. comments).
+
+## Using testharness.js for Manual Tests
+
+A convenient way to present the results of a test that can have the
+result determined by script after some manual setup steps is to use
+testharness.js to determine and present the result. In this case one
+must pass `{explicit_timeout: true}` in a call to `setup()` in order
+to disable the automatic timeout of the test. For example:
+
+```html
+<!doctype html>
+<title>Manual click on button triggers onclick handler</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+setup({explicit_timeout: true})
+</script>
+<p>Click on the button below. If a "PASS" result appears the test
+passes, otherwise it fails</p>
+<button onclick="done()">Click Here</button>
+```
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/print-reftests.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/print-reftests.md
new file mode 100644
index 0000000..62a037da
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/print-reftests.md
@@ -0,0 +1,45 @@
+# Print Reftests
+
+Print reftests are like ordinary [reftests](reftests), except that the
+output is rendered to pagninated form and then compared page-by-page
+with the reference.
+
+Print reftests are distinguished by the string `-print` in the
+filename immediately before the extension, or by being under a
+directory named `print`. Examples:
+
+- `css/css-foo/bar-print.html` is a print reftest
+- `css/css-foo/print/bar.html` is a print reftest
+- `css/css-foo/bar-print-001.html` is **not** a print reftest
+
+
+Like ordinary reftests, the reference is specified using a `<link
+rel=match>` element.
+
+The default page size for print reftests is 12.7 cm by 7.62 cm (5
+inches by 3 inches).
+
+All the features of ordinary reftests also work with print reftests
+including [fuzzy matching](reftests.html#fuzzy-matching). Any fuzzy
+specifier applies to each image comparison performed i.e. separately
+for each page.
+
+## Page Ranges
+
+In some cases it may be desirable to only compare a subset of the
+output pages in the reftest. This is possible using
+```
+<meta name=reftest-pages content=[range-specifier]>
+```
+Where a range specifier has the form
+```
+range-specifier = <specifier-item> ["," <specifier-item>]*
+specifier-item = <int> | <int>? "-" <int>?
+```
+
+For example to specify rendering pages 1 and 2, 4, 6 and 7, and 9 and
+10 of a 10 page page document one could write:
+
+```
+<meta name=reftest-pages content="-2,4,6,7,9-">
+```
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/python-handlers/index.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/python-handlers/index.md
new file mode 100644
index 0000000..e3be148
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/python-handlers/index.md
@@ -0,0 +1,96 @@
+# Python Handlers
+
+Python file handlers are Python files which the server executes in response to
+requests made to the corresponding URL. This is hooked up to a route like
+`("*", "*.py", python_file_handler)`, meaning that any .py file will be
+treated as a handler file (note that this makes it easy to write unsafe
+handlers, particularly when running the server in a web-exposed setting).
+
+The Python files must define a function named `main` with the signature:
+
+    main(request, response)
+
+...where `request` is [a wptserve `Request`
+object](/tools/wptserve/docs/request) and `response` is [a wptserve `Response`
+object](/tools/wptserve/docs/response).
+
+This function must return a value in one of the following four formats:
+
+    ((status_code, reason), headers, content)
+    (status_code, headers, content)
+    (headers, content)
+    content
+
+Above, `headers` is a list of (field name, value) pairs, and `content` is a
+string or an iterable returning strings.
+
+The `main` function may also update the response manually. For example, one may
+use `response.headers.set` to set a response header, and only return the
+content. One may even use this kind of handler, but manipulate the output
+socket directly. The `writer` property of the response exposes a
+`ResponseWriter` object that allows writing specific parts of the request or
+direct access to the underlying socket. If used, the return value of the
+`main` function and the properties of the `response` object will be ignored.
+
+The wptserver implements a number of Python APIs for controlling traffic.
+
+```eval_rst
+.. toctree::
+   :maxdepth: 1
+
+   /tools/wptserve/docs/request
+   /tools/wptserve/docs/response
+   /tools/wptserve/docs/stash
+```
+
+### Python3 compatibility
+
+Even though Python3 is not fully supported at this point, some work is being
+done to add compatibility for it. This is why you can see in multiple places
+the use of the `six` python module which is meant to provide a set of simple
+utilities that work for both generation of python (see
+[docs](https://six.readthedocs.io/)). The module is vendored in
+tools/third_party/six/six.py.
+
+When an handler is added, it should be at least syntax-compatible with Python3.
+You can check that by running:
+```
+python3 -m py_compile <path/to/handler.py>
+```
+
+## Example: Dynamic HTTP headers
+
+The following code defines a Python handler that allows the requester to
+control the value of the `Content-Type` HTTP response header:
+
+```python
+def main(request, response):
+    content_type = request.GET.first('content-type')
+    headers = [('Content-Type', content_type)]
+
+    return (200, 'my status text'), headers, 'my response content'
+```
+
+If saved to a file named `resources/control-content-type.py`, the WPT server
+will respond to requests for `resources/control-content-type.py` by executing
+that code.
+
+This could be used from a [testharness.js test](../testharness) like so:
+
+```html
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Demonstrating the WPT server's Python handler feature</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test(function() {
+  return fetch('resources/control-content-type.py?content-type=text/foobar')
+    .then(function(response) {
+      assert_equals(response.status, 200);
+      assert_equals(response.statusText, 'my status text');
+      assert_equals(response.headers.get('Content-Type'), 'text/foobar');
+    });
+});
+</script>
+```
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/reftest-tutorial.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/reftest-tutorial.md
new file mode 100644
index 0000000..a514309
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/reftest-tutorial.md
@@ -0,0 +1,276 @@
+# Writing a reftest
+
+<!--
+Note to maintainers:
+
+This tutorial is designed to be an authentic depiction of the WPT contribution
+experience. It is not intended to be comprehensive; its scope is intentionally
+limited in order to demonstrate authoring a complete test without overwhelming
+the reader with features. Because typical WPT usage patterns change over time,
+this should be updated periodically; please weigh extensions against the
+demotivating effect that a lengthy guide can have on new contributors.
+-->
+
+Let's say you've discovered that WPT doesn't have any tests for the `dir`
+attribute of [the `<bdo>`
+element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/bdo). This
+tutorial will guide you through the process of writing and submitting a test.
+You'll need to [configure your system to use WPT's
+tools](../running-tests/from-local-system), but you won't need them until
+towards the end of this tutorial. Although it includes some very brief
+instructions on using git, you can find more guidance in [the tutorial for git
+and GitHub](../writing-tests/github-intro).
+
+WPT's reftests are great for testing web-platform features that have some
+visual effect. [The reftests reference page](reftests) describes them in the
+abstract, but for the purposes of this guide, we'll only consider the features
+we need to test the `<bdo>` element.
+
+```eval_rst
+.. contents::
+   :local:
+```
+
+## Setting up your workspace
+
+To make sure you have the latest code, first type the following into a terminal
+located in the root of the WPT git repository:
+
+    $ git fetch git@github.com:web-platform-tests/wpt.git
+
+Next, we need a place to store the change set we're about to author. Here's how
+to create a new git branch named `reftest-for-bdo` from the revision of WPT we
+just downloaded:
+
+    $ git checkout -b reftest-for-bdo FETCH_HEAD
+
+Now you're ready to create your patch.
+
+## Writing the test file
+
+First, we'll create a file that demonstrates the "feature under test." That is:
+we'll write an HTML document that displays some text using a `<bdo>` element.
+
+WPT has thousands of tests, so it can be daunting to decide where to put a new
+one. Generally speaking, [test files should be placed in directories
+corresponding to the specification text they are
+verifying](../test-suite-design). `<bdo>` is defined in [the "text-level
+semantics" chapter of the HTML
+specification](https://html.spec.whatwg.org/multipage/text-level-semantics.html),
+so we'll want to create our new test in the directory
+`html/semantics/text-level-semantics/the-bdo-element/`. Create a file named
+`rtl.html` and open it in your text editor.
+
+Here's one way to demonstrate the feature:
+
+```html
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>BDO element dir=rtl</title>
+<link rel="help" href="https://html.spec.whatwg.org/#the-bdo-element">
+<meta name="assert" content="BDO element's DIR content attribute renders corrently given value of 'rtl'.">
+
+<p>Test passes if WAS is displayed below.</p>
+<bdo dir="rtl">SAW</bdo>
+```
+
+That's pretty dense! Let's break it down:
+
+- ```html
+  <!DOCTYPE html>
+  <meta charset="utf-8">
+  ```
+
+  We explicitly set the DOCTYPE and character set to be sure that browsers
+  don't infer them to be something we aren't expecting. We're omitting the
+  `<html>` and `<head>` tags. That's a common practice in WPT, preferred
+  because it makes tests more concise.
+
+- ```html
+  <title>BDO element dir=rtl</title>
+  ```
+  The document's title should succinctly describe the feature under test.
+
+- ```html
+  <link rel="help" href="https://html.spec.whatwg.org/#the-bdo-element">
+  ```
+
+  The "help" metadata should reference the specification under test so that
+  everyone understands the motivation. This is so helpful that [the CSS Working
+  Group requires it for CSS tests](css-metadata)! If you're writing a reftest
+  for a feature outside of CSS, feel free to omit this tag.
+
+- ```html
+  <meta name="assert" content="BDO element's DIR content attribute renders corrently given value of 'rtl'.">
+  ```
+
+  The "assert" metadata is a structured way for you to describe exactly what
+  you want your reftest to verify. For a direct test like the one we're writing
+  here, it might seem a little superfluous. It's much more helpful for
+  more-involved tests where reviewers might need some help understanding your
+  intentions.
+
+  This tag is optional, so you can skip it if you think it's unnecessary. We
+  recommend using it for your first few tests since it may let reviewers give
+  you more helpful feedback. As you get more familiar with WPT and the
+  specifications, you'll get a sense for when and where it's better to leave it
+  out.
+
+- ```html
+  <p>Test passes if WAS is displayed below.</p>
+  ```
+
+  We're communicating the "pass" condition in plain English to make the test
+  self-describing.
+
+- ```html
+  <bdo dir="rtl">SAW</bdo>
+  ```
+
+  This is the real focus of the test. We're including some text inside a
+  `<bdo>` element in order to demonstrate the feature under test.
+
+Since this page doesn't rely on any [special WPT server
+features](server-features), we can view it by loading the HTML file directly.
+There are a bunch of ways to do this; one is to navigate to the
+`html/semantics/text-level-semantics/the-bdo-element/` directory in a file
+browser and drag the new `rtl.html` file into an open web browser window.
+
+![](/assets/reftest-tutorial-test-screenshot.png "screen shot of the new test")
+
+Sighted people can open that document and verify whether or not the stated
+expectation is satisfied. If we were writing a [manual test](manual), we'd be
+done. However, it's time-consuming for a human to run tests, so we should
+prefer making tests automatic whenever possible. Remember that we set out to
+write a "reference test." Now it's time to write the reference file.
+
+## Writing a "match" reference
+
+The "match" reference file describes what the test file is supposed to look
+like. Critically, it *must not* use the technology that we are testing. The
+reference file is what allows the test to be run by a computer--the computer
+can verify that each pixel in the test document exactly matches the
+corresponding pixel in the reference document.
+
+Make a new file in the same
+`html/semantics/text-level-semantics/the-bdo-element/` directory named
+`rtl-ref.html`, and save the following markup into it:
+
+```html
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>BDO element dir=rtl reference</title>
+
+<p>Test passes if WAS is displayed below.</p>
+<p>WAS</p>
+```
+
+This is like a stripped-down version of the test file. In order to produce a
+visual rendering which is the same as the expected rendering, it uses a `<p>`
+element whose contents is the characters in right-to-left order. That way, if
+the browser doesn't support the `<bdo>` element, this file will still show text
+in the correct sequence.
+
+This file is also completely functional without the WPT server, so you can open
+it in a browser directly from your hard drive.
+
+Currently, there's no way for a human operator or an automated script to know
+that the two files we've created are supposed to match visually. We'll need to
+add one more piece of metadata to the test file we created earlier. Open
+`html/semantics/text-level-semantics/the-bdo-element/rtl.html` in your text
+editor and add another `<link>` tag as described by the following change
+summary:
+
+```diff
+ <!DOCTYPE html>
+ <meta charset="utf-8">
+ <title>BDO element dir=rtl</title>
+ <link rel="author" title="Sam Smith" href="mailto:sam@example.com">
+ <link rel="help" href="https://html.spec.whatwg.org/#the-bdo-element">
++<link rel="match" href="rtl-ref.html">
+ <meta name="assert" content="BDO element's DIR content attribute renders corrently given value of 'rtl'.">
+
+ <p>Test passes if WAS is displayed below.</p>
+ <bdo dir="rtl">SAW</bdo>
+```
+
+Now, anyone (human or computer) reviewing the test file will know where to find
+the associated reference file.
+
+## Verifying our work
+
+We're done writing the test, but we should make sure it fits in with the rest
+of WPT before we submit it. This involves using some of the project's tools, so
+this is the point you'll need to [configure your system to run
+WPT](../running-tests/from-local-system).
+
+[The lint tool](lint-tool) can detect some of the common mistakes people make
+when contributing to WPT. To run it, open a command-line terminal, navigate to
+the root of the WPT repository, and enter the following command:
+
+    python ./wpt lint html/semantics/text-level-semantics/the-bdo-element
+
+If this recognizes any of those common mistakes in the new files, it will tell
+you where they are and how to fix them. If you do have changes to make, you can
+run the command again to make sure you got them right.
+
+Now, we'll run the test using the automated pixel-by-pixel comparison approach
+mentioned earlier. This is important for reftests because the test and the
+reference may differ in very subtle ways that are hard to catch with the naked
+eye. That's not to say your test has to pass in all browsers (or even in *any*
+browser). But if we expect the test to pass, then running it this way will help
+us catch other kinds of mistakes.
+
+The tools support running the tests in many different browsers. We'll use
+Firefox this time:
+
+    python ./wpt run firefox html/semantics/text-level-semantics/the-bdo-element/rtl.html
+
+We expect this test to pass, so if it does, we're ready to submit it. If we
+were testing a web platform feature that Firefox didn't support, we would
+expect the test to fail instead.
+
+There are a few problems to look out for in addition to passing/failing status.
+The report will describe fewer tests than we expect if the test isn't run at
+all. That's usually a sign of a formatting mistake, so you'll want to make sure
+you've used the right file names and metadata. Separately, the web browser
+might crash. That's often a sign of a browser bug, so you should consider
+[reporting it to the browser's
+maintainers](https://rachelandrew.co.uk/archives/2017/01/30/reporting-browser-bugs/)!
+
+## Submitting the test
+
+First, let's stage the new files for committing:
+
+    $ git add html/semantics/text-level-semantics/the-bdo-element/rtl.html
+    $ git add html/semantics/text-level-semantics/the-bdo-element/rtl-ref.html
+
+We can make sure the commit has everything we want to submit (and nothing we
+don't) by using `git diff`:
+
+    $ git diff --staged
+
+On most systems, you can use the arrow keys to navigate through the changes,
+and you can press the `q` key when you're done reviewing.
+
+Next, we'll create a commit with the staged changes:
+
+    $ git commit -m '[html] Add test for the `<bdo>` element'
+
+And now we can push the commit to our fork of WPT:
+
+    $ git push origin reftest-for-bdo
+
+The last step is to submit the test for review. WPT doesn't actually need the
+test we wrote in this tutorial, but if we wanted to submit it for inclusion in
+the repository, we would create a pull request on GitHub. [The guide on git and
+GitHub](../writing-tests/github-intro) has all the details on how to do that.
+
+## More practice
+
+Here are some ways you can keep experimenting with WPT using this test:
+
+- Improve coverage by adding more tests for related behaviors (e.g. nested
+  `<bdo>` elements)
+- Add another reference document which describes what the test should *not*
+  look like using [`rel=mismatch`](reftests)
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/reftests.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/reftests.md
new file mode 100644
index 0000000..9f3165c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/reftests.md
@@ -0,0 +1,176 @@
+# Reftests
+
+Reftests are one of the primary tools for testing things relating to
+rendering; they are made up of the test and one or more other pages
+("references") with assertions as to whether they render identically
+or not. This page describes their aspects exhaustively; [the tutorial
+on writing a reftest](reftest-tutorial) offers a more limited but
+grounded guide to the process.
+
+## How to Run Reftests
+
+Reftests can be run manually simply by opening the test and the
+reference file in multiple windows or tabs and flipping between the
+two. In automation the comparison is done in an automated fashion,
+which can lead to differences hard for the human eye to notice to
+cause the test to fail.
+
+## Components of a Reftest
+
+In the simplest case, a reftest consists of a pair of files called the
+*test* and the *reference*.
+
+The *test* file is the one that makes use of the technology being
+tested. It also contains a `link` element with `rel="match"` or
+`rel="mismatch"` and `href` attribute pointing to the *reference*
+file, e.g. `<link rel=match href=references/green-box-ref.html>`. A
+`match` test only passes if the two files render pixel-for-pixel
+identically within a 800x600 window *including* scroll-bars if
+present; a `mismatch` test only passes if they *don't* render
+identically.
+
+The *reference* file is typically written to be as simple as possible,
+and does not use the technology under test. It is desirable that the
+reference be rendered correctly even in UAs with relatively poor
+support for CSS and no support for the technology under test.
+
+## Writing a Good Reftest
+
+In general the files used in a reftest should follow
+the [general guidelines][] and
+the [rendering test guidelines][rendering]. They should also be
+self-describing, to allow a human to determine whether the the
+rendering is as expected.
+
+References can be shared between tests; this is strongly encouraged as
+it makes it easier to tell at a glance whether a test passes (through
+familiarity) and enables some optimizations in automated test
+runners. Shared references are typically placed in `references`
+directories, either alongside the tests they are expected to be useful
+for or at the top level if expected to be generally applicable (e.g.,
+many layout tests can be written such that the correct rendering is a
+100x100 green square!). For references that are applicable only to a
+single test, it is recommended to use the test name with a suffix of
+`-ref` as their filename; e.g., `test.html` would have `test-ref.html`
+as a reference.
+
+## Multiple References
+
+Sometimes, a test's pass condition cannot be captured in a single
+reference.
+
+If a test has multiple links, then the test passes if:
+
+ * If there are any match references, at least one must match, and
+ * If there are any mismatch references, all must mismatch.
+
+ If you need multiple matches to succeed, these can be turned into
+ multiple tests (for example, by just having a reference be a test
+ itself!). If this seems like an unreasonable restriction, please file
+ a bug and let us know!
+
+## Controlling When Comparison Occurs
+
+By default, reftest screenshots are taken after the following
+conditions are met:
+
+* The `load` event has fired
+* Web fonts (if any) are loaded
+* Pending paints have completed
+
+In some cases it is necessary to delay the screenshot later than this,
+for example because some DOM manipulation is required to set up the
+desired test conditions. To enable this, the test may have a
+`class="reftest-wait"` attribute specified on the root element. In
+this case the harness will run the following sequence of steps:
+
+* Wait for the `load` event to fire and fonts to load.
+* Wait for pending paints to complete.
+* Fire an event named `TestRendered` at the root element, with the
+  `bubbles` attribute set to true.
+* Wait for the `reftest-wait` class to be removed from the root
+  element.
+* Wait for pending paints to complete.
+* Screenshot the viewport.
+
+The `TestRendered` event provides a hook for tests to make
+modifications to the test document that are not batched into the
+initial layout/paint.
+
+## Fuzzy Matching
+
+In some situations a test may have subtle differences in rendering
+compared to the reference due to, e.g., anti-aliasing. To allow for
+these small differences, we allow tests to specify a fuzziness
+characterised by two parameters, both of which must be specified:
+
+ * A maximum difference in the per-channel color value for any pixel.
+ * A number of total pixels that may be different.
+
+The maximum difference in the per pixel color value is formally
+defined as follows: let <code>T<sub>x,y,c</sub></code> be the value of
+colour channel `c` at pixel coordinates `x`, `y` in the test image and
+<code>R<sub>x,y,c</sub></code> be the corresponding value in the
+reference image, and let <code>width</code> and <code>height</code> be
+the dimensions of the image in pixels. Then <code>maxDifference =
+max<sub>x=[0,width) y=[0,height), c={r,g,b}</sub>(|T<sub>x,y,c</sub> -
+R<sub>x,y,c</sub>|)</code>.
+
+To specify the fuzziness in the test file one may add a `<meta
+name=fuzzy>` element (or, in the case of more complex tests, to any
+page containing the `<link rel=[mis]match>` elements). In the simplest
+case this has a `content` attribute containing the parameters above,
+separated by a colon e.g.
+
+```
+<meta name=fuzzy content="maxDifference=15;totalPixels=300">
+```
+
+would allow for a  difference of exactly 15 / 255 on any color channel
+and 300 exactly pixels total difference. The argument names are optional
+and may be elided; the above is the same as:
+
+```
+<meta name=fuzzy content="15;300">
+```
+
+The values may also be given as ranges e.g.
+
+```
+<meta name=fuzzy content="maxDifference=10-15;totalPixels=200-300">
+```
+
+or
+
+```
+<meta name=fuzzy content="10-15;200-300">
+```
+
+In this case the maximum pixel difference must be in the range
+`10-15` and the total number of different pixels must be in the range
+`200-300`.
+
+In cases where a single test has multiple possible refs and the
+fuzziness is not the same for all refs, a ref may be specified by
+prefixing the `content` value with the relative url for the ref e.g.
+
+```
+<meta name=fuzzy content="option1-ref.html:10-15;200-300">
+```
+
+One meta element is required per reference requiring a unique
+fuzziness value, but any unprefixed value will automatically be
+applied to any ref that doesn't have a more specific value.
+
+## Limitations
+
+In some cases, a test cannot be a reftest. For example, there is no
+way to create a reference for underlining, since the position and
+thickness of the underline depends on the UA, the font, and/or the
+platform. However, once it's established that underlining an inline
+element works, it's possible to construct a reftest for underlining
+a block element, by constructing a reference using underlines on a
+```<span>``` that wraps all the content inside the block.
+
+[general guidelines]: general-guidelines
+[rendering]: rendering
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/rendering.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/rendering.md
new file mode 100644
index 0000000..e17b6ef
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/rendering.md
@@ -0,0 +1,84 @@
+# Rendering Test Guidelines
+
+There are a number of techniques typically used when writing rendering tests;
+these are especially using for [visual](visual) tests which need to be manually
+judged and following common patterns makes it easier to correctly tell if a
+given test passed or not.
+
+## Indicating success
+
+Success is largely indicated by the color green; typically in one of
+two ways:
+
+ * **The green paragraph**: arguably the simplest form of test, this
+   typically consists of single line of text with a pass condition of,
+   "This text should be green". A variant of this is using the
+   background instead, with a pass condition of, "This should have a
+   green background".
+
+ * **The green square**: applicable to many block layout tests, the test
+   renders a green square when it passes; these can mostly be written to
+   match [this][ref-filled-green-100px-square] reference. This green square is
+   often rendered over a red square, such that when the test fails there is red
+   visible on the page; this can even be done using text by using the
+   [Ahem][ahem] font.
+
+More occasionally, the entire canvas is rendered green, typically when
+testing parts of CSS that affect the entire page. Care has to be taken
+when writing tests like this that the test will not result in a single
+green paragraph if it fails. This is usually done by forcing the short
+descriptive paragraph to have a neutral color (e.g., white).
+
+Sometimes instead of a green square, a white square is used to ensure
+any red is obvious. To ensure the stylesheet has loaded, it is
+recommended to make the pass condition paragraph green and require
+that in addition to there being no red on the page.
+
+## Indicating failure
+
+In addition to having clearly defined characteristics when
+they pass, well designed tests should have some clear signs when
+they fail. It can sometimes be hard to make a test do something only
+when the test fails, because it is very hard to predict how user
+agents will fail! Furthermore, in a rather ironic twist, the best
+tests are those that catch the most unpredictable failures!
+
+Having said that, here are the best ways to indicate failures:
+
+ * Using the color red is probably the best way of highlighting
+   failures. Tests should be designed so that if the rendering is a
+   few pixels off some red is uncovered or otherwise rendered on the
+   page.
+
+ * Tests of the `line-height`, `font-size` and similar properties can
+   sometimes be devised in such a way that a failure will result in
+   the text overlapping.
+
+ * Some properties lend themselves well to making "FAIL" render in the
+   case of something going wrong, for example `quotes` and
+   `content`.
+
+## Other Colors
+
+Aside from green and red, other colors are generally used in specific
+ways:
+
+ * Black is typically used for descriptive text,
+
+ * Blue is frequently used as an obvious color for tests with complex
+   pass conditions,
+
+ * Fuchsia, yellow, teal, and orange are typically used when multiple
+   colors are needed,
+
+ * Dark gray is often used for descriptive lines, and
+
+ * Silver or light gray is often used for irrelevant content, such as
+   filler text.
+
+None of these rules are absolute because testing
+color-related functionality will necessitate using some of these
+colors!
+
+[ref-filled-green-100px-square]: https://github.com/w3c/csswg-test/blob/master/reference/ref-filled-green-100px-square.xht
+[ahem]: ahem
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/server-features.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/server-features.md
new file mode 100644
index 0000000..980a27d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/server-features.md
@@ -0,0 +1,155 @@
+# Server Features
+
+For many tests, writing one or more static HTML files is
+sufficient. However there are a large class of tests for which this
+approach is insufficient, including:
+
+* Tests that require cross-domain access
+
+* Tests that depend on setting specific headers or status codes
+
+* Tests that need to inspect the browser-sent request
+
+* Tests that require state to be stored on the server
+
+* Tests that require precise timing of the response.
+
+To make writing such tests possible, we are using a number of
+server-side components designed to make it easy to manipulate the
+precise details of the response:
+
+* *wptserve*, a custom Python HTTP server
+
+* *pywebsocket*, an existing websockets server
+
+* *tools/quic*, a custom Python 3 QUIC server using `aioquic`
+
+wptserve is a Python-based web server. By default it serves static
+files in the test suite. For more sophisticated requirements, several
+mechanisms are available to take control of the response. These are
+outlined below.
+
+### Tests Involving Multiple Origins
+
+Our test servers are guaranteed to be accessible through two domains
+and five subdomains under each. The 'main' domain is unnamed; the
+other is called 'alt'. These subdomains are: `www`, `www1`, `www2`,
+`天気の良い日`, and `élève`; there is also `nonexistent` which is
+guaranteed not to resolve. In addition, the HTTP server listens on two
+ports, and the WebSockets server on one. These subdomains and ports
+must be used for cross-origin tests.
+
+Tests must not hardcode the hostname of the server that they expect to
+be running on or the port numbers, as these are not guaranteed by the
+test environment. Instead they can get this information in one of two
+ways:
+
+* From script, using the `location` API.
+
+* By using a textual substitution feature of the server.
+
+In order for the latter to work, a file must either have a name of the form
+`{name}.sub.{ext}` e.g. `example-test.sub.html` or be referenced through a URL
+containing `pipe=sub` in the query string e.g. `example-test.html?pipe=sub`.
+The substitution syntax uses `{{ }}` to delimit items for substitution. For
+example to substitute in the main host name, one would write: `{{host}}`.
+
+To get full domains, including subdomains, there is the `hosts` dictionary,
+where the first dimension is the name of the domain, and the second the
+subdomain. For example, `{{hosts[][www]}}` would give the `www` subdomain under
+the main (unnamed) domain, and `{{hosts[alt][élève]}}` would give the `élève`
+subdomain under the alt domain.
+
+For mostly historic reasons, the subdomains of the main domain are
+also available under the `domains` dictionary; this is identical to
+`hosts[]`.
+
+Ports are also available on a per-protocol basis. For example,
+`{{ports[ws][0]}}` is replaced with the first (and only) WebSockets port, while
+`{{ports[http][1]}}` is replaced with the second HTTP port.
+
+The request URL itself can be used as part of the substitution using the
+`location` dictionary, which has entries matching the `window.location` API.
+For example, `{{location[host]}}` is replaced by `hostname:port` for the
+current request, matching `location.host`.
+
+
+### Tests Requiring Special Headers
+
+For tests requiring that a certain HTTP header is set to some static
+value, a file with the same path as the test file except for an an
+additional `.headers` suffix may be created. For example for
+`/example/test.html`, the headers file would be
+`/example/test.html.headers`. This file consists of lines of the form
+
+    header-name: header-value
+
+For example
+
+    Content-Type: text/html; charset=big5
+
+To apply the same headers to all files in a directory use a
+`__dir__.headers` file. This will only apply to the immediate
+directory and not subdirectories.
+
+Headers files may be used in combination with substitutions by naming
+the file e.g. `test.html.sub.headers`.
+
+
+### Tests Requiring Full Control Over The HTTP Response
+
+```eval_rst
+.. toctree::
+   :maxdepth: 1
+
+   python-handlers/index
+   server-pipes
+```
+
+For full control over the request and response, the server provides the ability
+to write `.asis` files; these are served as literal HTTP responses. In other
+words, they are sent byte-for-byte to the server without adding an HTTP status
+line, headers, or anything else. This makes them suitable for testing
+situations where the precise bytes on the wire are static, and control over the
+timing is unnecessary, but the response does not conform to HTTP requirements.
+
+The server also provides the ability to write [Python
+"handlers"](python-handlers/index)--Python scripts that have access to request
+data and can manipulate the content and timing of the response. Responses are
+also influenced by [the `pipe` query string parameter](server-pipes).
+
+
+### Tests Requiring HTTP/2.0
+
+The server now has a prototype HTTP/2.0 server which gives you access to
+some of the HTTP/2.0 specific functionality. Currently, the server is off
+by default and needs to be run using `./wpt serve --h2` in order to enable it.
+The HTTP/2.0 server supports handlers that work per-frame; these, along with the
+API are documented in [Writing H2 Tests](h2tests).
+
+> <b>Important:</b> The HTTP/2.0 server requires you to have Python 2.7.10+
+and OpenSSL 1.0.2+. This is because HTTP/2.0 is negotiated using the
+[TLS ALPN](https://tools.ietf.org/html/rfc7301) extension, which is only
+supported in
+[OpenSSL 1.0.2](https://www.openssl.org/news/openssl-1.0.2-notes.html) and up.
+
+
+### Tests Requiring QUIC
+
+We do not support loading a test over QUIC yet, but a test can establish a QUIC
+connection to the test server (e.g. for WebTransport, similar to WebSocket).
+Since the QUIC server is not yet enabled by default, tests must explicitly
+declare that they need access to the QUIC server:
+
+* For HTML tests (including testharness.js and reference tests), add the
+  following element:
+```html
+<meta name="quic" content="true">
+```
+* For JavaScript tests (auto-generated tests), add the following comment:
+```js
+// META: quic=true
+```
+
+The QUIC server is not yet enabled by default, so QUIC tests will be skipped
+unless `--enable-quic` is specified to `./wpt run`.
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/server-pipes.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/server-pipes.md
new file mode 100644
index 0000000..4f4011a6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/server-pipes.md
@@ -0,0 +1,144 @@
+# wptserve Pipes
+
+Pipes are designed to allow simple manipulation of the way that
+static files are sent without requiring any custom code. They are also
+useful for cross-origin tests because they can be used to activate a
+substitution mechanism which can fill in details of ports and server
+names in the setup on which the tests are being run.
+
+## Enabling
+
+Pipes are functions that may be used when serving files to alter parts
+of the response. These are invoked by adding a pipe= query parameter
+taking a | separated list of pipe functions and parameters. The pipe
+functions are applied to the response from left to right. For example:
+
+    GET /sample.txt?pipe=slice(1,200)|status(404).
+
+This would serve bytes 1 to 199, inclusive, of foo.txt with the HTTP status
+code 404.
+
+Note: If you write directly to the response socket using ResponseWriter, or
+when using the asis handler, only the trickle pipe will affect the response.
+
+There are several built-in pipe functions, and it is possible to add
+more using the `@pipe` decorator on a function, if required.
+
+Note: Because of the way pipes compose, using some pipe functions prevents the
+content-length of the response from being known in advance. In these cases the
+server will close the connection to indicate the end of the response,
+preventing the use of HTTP 1.1 keepalive.
+
+## Built-In Pipes
+
+### `sub`
+
+Used to substitute variables from the server environment, or from the
+request into the response. A typical use case is for testing
+cross-domain since the exact domain name and ports of the servers are
+generally unknown.
+
+Substitutions are marked in a file using a block delimited by `{{`
+and `}}`. Inside the block the following variables are available:
+
+- `{{host}}` - The host name of the server excluding any subdomain part.
+- `{{domains[]}}` - The domain name of a particular subdomain e.g.
+  `{{domains[www]}}` for the `www` subdomain.
+- `{{ports[][]}}` - The port number of servers, by protocol e.g.
+  `{{ports[http][0]}}` for the first (and, depending on setup, possibly only)
+  http server
+- `{{headers[]}}` The HTTP headers in the request e.g. `{{headers[X-Test]}}`
+  for a hypothetical `X-Test` header.
+- `{{header_or_default(header, default)}}` The value of an HTTP header, or a
+  default value if it is absent. e.g. `{{header_or_default(X-Test,
+  test-header-absent)}}`
+- `{{GET[]}}` The query parameters for the request e.g. `{{GET[id]}}` for an id
+  parameter sent with the request.
+
+So, for example, to write a JavaScript file called `xhr.js` that
+depends on the host name of the server, without hardcoding, one might
+write:
+
+    var server_url = http://{{host}}:{{ports[http][0]}}/path/to/resource;
+    //Create the actual XHR and so on
+
+The file would then be included as:
+
+    <script src="xhr.js?pipe=sub"></script>
+
+This pipe can also be enabled by using a filename `*.sub.ext`, e.g. the file above could be called `xhr.sub.js`.
+
+### `status`
+
+Used to set the HTTP status of the response, for example:
+
+    example.js?pipe=status(410)
+
+### `headers`
+
+Used to add or replace http headers in the response. Takes two or
+three arguments; the header name, the header value and whether to
+append the header rather than replace an existing header (default:
+False). So, for example, a request for:
+
+    example.html?pipe=header(Content-Type,text/plain)
+
+causes example.html to be returned with a text/plain content type
+whereas:
+
+    example.html?pipe=header(Content-Type,text/plain,True)
+
+Will cause example.html to be returned with both text/html and
+text/plain content-type headers.
+
+### `slice`
+
+Used to send only part of a response body. Takes the start and,
+optionally, end bytes as arguments, although either can be null to
+indicate the start or end of the file, respectively. So for example:
+
+    example.txt?pipe=slice(10,20)
+
+Would result in a response with a body containing 10 bytes of
+example.txt including byte 10 but excluding byte 20.
+
+    example.txt?pipe=slice(10)
+
+Would cause all bytes from byte 10 of example.txt to be sent, but:
+
+    example.txt?pipe=slice(null,20)
+
+Would send the first 20 bytes of example.txt.
+
+### `trickle`
+
+Note: Using this function will force a connection close.
+
+Used to send the body of a response in chunks with delays. Takes a
+single argument that is a microsyntax consisting of colon-separated
+commands. There are three types of commands:
+
+* Bare numbers represent a number of bytes to send
+
+* Numbers prefixed `d` indicate a delay in seconds
+
+* Numbers prefixed `r` must only appear at the end of the command, and
+  indicate that the preceding N items must be repeated until there is
+  no more content to send. The number of items to repeat must be even.
+
+In the absence of a repetition command, the entire remainder of the content is
+sent at once when the command list is exhausted. So for example:
+
+    example.txt?pipe=trickle(d1)
+
+causes a 1s delay before sending the entirety of example.txt.
+
+    example.txt?pipe=trickle(100:d1)
+
+causes 100 bytes of example.txt to be sent, followed by a 1s delay,
+and then the remainder of the file to be sent. On the other hand:
+
+    example.txt?pipe=trickle(100:d1:r2)
+
+Will cause the file to be sent in 100 byte chunks separated by a 1s
+delay until the whole content has been sent.
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/submission-process.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/submission-process.md
new file mode 100644
index 0000000..c6268f9b1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/submission-process.md
@@ -0,0 +1,64 @@
+# Submitting Tests
+
+Test submission is via the typical [GitHub workflow][github flow]. For detailed
+guidelines on setup and each of these steps, please refer to the [Github Test
+Submission](github-intro) documentation.
+
+* Fork the [GitHub repository][repo].
+
+* Create a feature branch for your changes.
+
+* Make your changes.
+
+* Run the `lint` script in the root of your checkout to detect common
+  mistakes in test submissions. There is [detailed documentation for the lint
+  tool](lint-tool).
+
+* Commit your changes.
+
+* Push your local branch to your GitHub repository.
+
+* Using the GitHub UI, create a Pull Request for your branch.
+
+* When you get review comments, make more commits to your branch to
+  address the comments.
+
+* Once everything is reviewed and all issues are addressed, your pull
+  request will be automatically merged.
+
+We can sometimes take a little while to go through pull requests because we
+have to go through all the tests and ensure that they match the specification
+correctly. But we look at all of them, and take everything that we can.
+
+Hop on to the [mailing list][public-test-infra] or [IRC][]
+([webclient][web irc], join channel `#testing`) if you have an issue.  There is
+no need to announce your review request, as soon as you make a Pull Request
+GitHub will inform interested parties.
+
+## Previews
+
+The website [http://w3c-test.org](http://w3c-test.org) exists to help
+contributors demonstrate their proposed changes to others. If you are [a GitHub
+collaborator](https://help.github.com/en/articles/permission-levels-for-a-user-account-repository)
+on WPT, then the content of your pull requests will be available at
+`http://w3c-test.org/submissions/{{pull request ID}}`, where "pull request ID"
+is the numeric identifier for the pull request.
+
+For example, a pull request at https://github.com/web-platform-tests/wpt/pull/3
+has a pull request ID `3`. Its contents can be viewed at
+http://w3c-test.org/submissions/3.
+
+If you are *not* a GitHub collaborator, then your submission may be made
+available if a collaborator makes the following comment on your pull request:
+"w3c-test:mirror".
+
+Previews are not created automatically for non-collaborators because the WPT
+server will execute Python code in the mirrored submissions. Collaborators are
+encouraged to enable the preview by making the special comment only if they
+trust the authors not to submit malicious code.
+
+[repo]: https://github.com/web-platform-tests/wpt/
+[github flow]: https://guides.github.com/introduction/flow/
+[public-test-infra]: https://lists.w3.org/Archives/Public/public-test-infra/
+[IRC]: irc://irc.w3.org:6667/testing
+[web irc]: http://irc.w3.org
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/test-templates.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/test-templates.md
new file mode 100644
index 0000000..e8f4bfe7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/test-templates.md
@@ -0,0 +1,168 @@
+# Test Templates
+
+This page contains templates for creating tests. The template syntax
+is compatible with several popular editors including TextMate, Sublime
+Text, and emacs' YASnippet mode.
+
+Templates for filenames are also given. In this case `{}` is used to
+delimit text to be replaced and `#` represents a digit.
+
+## Reftests
+
+### HTML test
+
+<!--
+  Syntax highlighting cannot be enabled for the following template because it
+  contains invalid CSS.
+-->
+
+```
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>${1:Test title}</title>
+<link rel="match" href="${2:URL of match}">
+<style>
+    ${3:Test CSS}
+</style>
+<body>
+    ${4:Test content}
+</body>
+```
+
+Filename: `{test-topic}-###.html`
+
+### HTML reference
+
+<!--
+  Syntax highlighting cannot be enabled for the following template because it
+  contains invalid CSS.
+-->
+
+```
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>${1:Reference title}</title>
+<style>
+    ${2:Reference CSS}
+</style>
+<body>
+    ${3:Reference content}
+</body>
+```
+
+Filename: `{description}.html` or `{test-topic}-###-ref.html`
+
+### SVG test
+
+``` xml
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml">
+  <title>${1:Test title}</title>
+  <metadata>
+    <h:link rel="help" href="${2:Specification link}"/>
+    <h:link rel="match" href="${3:URL of match}"/>
+  </metadata>
+  ${4:Test body}
+</svg>
+```
+
+Filename: `{test-topic}-###.svg`
+
+### SVG reference
+
+``` xml
+<svg xmlns="http://www.w3.org/2000/svg">
+  <title>${1:Reference title}</title>
+  ${2:Reference content}
+</svg>
+```
+
+Filename: `{description}.svg` or `{test-topic}-###-ref.svg`
+
+## testharness.js tests
+
+### HTML
+
+``` html
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>${1:Test title}</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+${2:Test body}
+</script>
+```
+
+Filename: `{test-topic}-###.html`
+
+### HTML with [testdriver automation](testdriver)
+``` html
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>${1:Test title}</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<script>
+${2:Test body}
+</script>
+```
+
+Filename: `{test-topic}-###.html`
+
+### SVG
+
+``` xml
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml">
+  <title>${1:Test title}</title>
+  <metadata>
+    <h:link rel="help" href="${2:Specification link}"/>
+  </metadata>
+  <h:script src="/resources/testharness.js"/>
+  <h:script src="/resources/testharnessreport.js"/>
+  <script><![CDATA[
+  ${4:Test body}
+  ]]></script>
+</svg>
+```
+
+Filename: `{test-topic}-###.svg`
+
+### Manual Test
+
+#### HTML
+
+``` html
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>${1:Test title}</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+setup({explicit_timeout: true});
+${2:Test body}
+</script>
+```
+
+Filename: `{test-topic}-###-manual.html`
+
+#### SVG
+
+``` xml
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml">
+  <title>${1:Test title}</title>
+  <metadata>
+    <h:link rel="help" href="${2:Specification link}"/>
+  </metadata>
+  <h:script src="/resources/testharness.js"/>
+  <h:script src="/resources/testharnessreport.js"/>
+  <script><![CDATA[
+  setup({explicit_timeout: true});
+  ${4:Test body}
+  ]]></script>
+</svg>
+```
+
+Filename: `{test-topic}-###-manual.svg`
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/testdriver-extension-tutorial.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/testdriver-extension-tutorial.md
new file mode 100644
index 0000000..a2d42e00
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/testdriver-extension-tutorial.md
@@ -0,0 +1,350 @@
+# Testdriver extension tutorial
+Adding new commands to testdriver.js
+
+## Assumptions
+We assume the following in this writeup:
+ - You know what web-platform-tests is and you have a working checkout and can run tests
+ - You know what WebDriver is
+ - Familiarity with JavaScript and Python
+
+## Introduction!
+
+Let's implement window resizing. We can do this via the [Set Window Rect](https://w3c.github.io/webdriver/#set-window-rect) command in WebDriver.
+
+First, we need to think of what the API will look like a little. We will be using WebDriver and Marionette for this, so we can look and see that they take in x, y coordinates, width and height integers.
+
+The first part of this will be browser agnostic, but later we will need to implement a specific layer for each browser (here we will do Firefox and Chrome).
+
+## Code!
+
+### [resources/testdriver.js](https://github.com/web-platform-tests/wpt/blob/master/resources/testdriver.js)
+
+This is the main entry point the tests get. Here we need to add a function to the `test_driver` object that will call the `test_driver_internal` object.
+
+```javascript
+window.test_driver = {
+
+    // other commands...
+
+    /**
+    * Triggers browser window to be resized and relocated
+    *
+    * This matches the behaviour of the {@link
+    * https://w3c.github.io/webdriver/#set-window-rect|WebDriver
+    * Set Window Rect command}.
+    *
+    * @param {Integer} x - The x coordinate of the top left of the window
+    * @param {Integer} y - The y coordinate of the top left of the window
+    * @param {Integer} width - The width of the window
+    * @param {Integer} height - The width of the window
+    * @returns {Promise} fulfilled after window rect is set occurs, or rejected in
+    *                    the cases the WebDriver command errors
+    */
+    set_window_rect: function(x, y, width, height) {
+        return window.test_driver_internal.set_element_rect(x, y, width, height);
+    }
+```
+
+In the same file, lets add to the internal object. ( do we need to do this?) (make sure to do this if the internal call has different arguments than the external call, especially if it calls multiple internal calls)
+
+```javascript
+window.test_driver_internal = {
+
+    // other commands...
+
+    /**
+     * Triggers browser window to be resized and relocated
+     *
+     * This matches the behaviour of the {@link
+     * https://w3c.github.io/webdriver/#set-window-rect|WebDriver
+     * Set Window Rect command}.
+     *
+     * @param {Integer} x - The x coordinate of the top left of the window
+     * @param {Integer} y - The x coordinate of the top left of the window
+     * @param {Integer} width - The width of the window
+     * @param {Integer} height - The height of the window
+     * @returns {Promise} fulfilled after window rect is set occurs, or rejected in
+     *                    the cases the WebDriver command errors
+     */
+    set_window_rect: function(x, y, width, height) {
+        return Promise.reject(new Error("unimplemented"))
+    }
+```
+We will leave this unimplemented and override it in another file. Lets do that now!
+
+### [wptrunner/wptrunner/testdriver-extra.js](https://github.com/web-platform-tests/wpt/blob/master/tools/wptrunner/wptrunner/testdriver-extra.js)
+
+This will be the default function called when invoking the test driver commands (sometimes it is overridden by testdriver-vendor.js, but this is outside the scope of this writeup).
+
+```javascript
+window.test_driver_internal.set_element_rect = function(x, y, width, height) {
+    const pending_promise = new Promise(function(resolve, reject) {
+        pending_resolve = resolve;
+        pending_reject = reject;
+    });
+    window.opener.postMessage(
+        {"type": "action", "action": "set_window_rect", "x": x, "y": y, "width": width, "height": height}, "*");
+    return pending_promise;
+};
+```
+The main thing here is the `postMessage` argument. The first argument is an object with properties
+ - `type`: this always has to be the string `"action"`
+ - `action`: the name of the testdriver command this defines (in this case, `set_window_rect`)
+ - any other things you want to pass to the next point of execution (in this case, the x, y coordinates and the width and height)
+
+<!-- The pending promise needs to be there as it is resolved when the window receives a completion message from the executor. -->
+The pending promise is out of scope of this function and is resolved when the window receives a completion message from the executor.
+This happens here in the same file:
+
+```javascript
+    let pending_resolve = null;
+    let pending_reject = null;
+    let result = null;
+    window.addEventListener("message", function(event) {
+        const data = event.data;
+
+        if (typeof data !== "object" && data !== null) {
+            return;
+        }
+
+        if (data.type !== "testdriver-complete") {
+            return;
+        }
+
+        if (data.status === "success") {
+            result = JSON.parse(data.message).result
+            pending_resolve(result);
+        } else {
+            pending_reject();
+        }
+    });
+```
+
+One limitation this introduces is that only one testdriver call can be made at one time since the `pending_resolve` and `pending_reject` variables are in an outer scope.
+
+Next, this is passed to the executor and protocol in wptrunner. Time to switch to Python!
+
+[tools/wptrunner/wptrunner/executors/protocol.py](https://github.com/web-platform-tests/wpt/blob/master/tools/wptrunner/wptrunner/executors/protocol.py)
+
+```python
+class SetWindowRectProtocolPart(ProtocolPart):
+    """Protocol part for resizing and changing location of window"""
+    __metaclass__ = ABCMeta
+
+    name = "set_window_rect"
+
+    @abstractmethod
+    def set_window_rect(self, x, y, width, height):
+        """Change the window rect
+
+        :param x: The x coordinate of the top left of the window.
+        :param y: The y coordinate of the top left of the window.
+        :param width: The width of the window.
+        :param height: The height of the window."""
+        pass
+```
+
+Next we change the base executor.
+
+[tools/wptrunner/wptrunner/executors/base.py](https://github.com/web-platform-tests/wpt/blob/master/tools/wptrunner/wptrunner/executors/base.py)
+
+```python
+class CallbackHandler(object):
+    """Handle callbacks from testdriver-using tests.
+
+    The default implementation here makes sense for things that are roughly like
+    WebDriver. Things that are more different to WebDriver may need to create a
+    fully custom implementation."""
+
+    def __init__(self, logger, protocol, test_window):
+        self.protocol = protocol
+        self.test_window = test_window
+        self.logger = logger
+        self.callbacks = {
+            "action": self.process_action,
+            "complete": self.process_complete
+        }
+
+        self.actions = {
+            "click": ClickAction(self.logger, self.protocol),
+            "send_keys": SendKeysAction(self.logger, self.protocol),
+            {other actions},
+            "set_window_rect": SetWindowRectAction(self.logger, self.protocol) # add this!
+        }
+```
+
+```python
+class SetWindowRectAction(object):
+    def __init__(self, logger, protocol):
+        self.logger = logger
+        self.protocol = protocol
+
+    def __call__(self, payload):
+        x, y, width, height = payload["x"], payload["y"], payload["width"], payload["height"]
+        self.logger.debug("Setting window rect to be: x=%s, y=%s, width=%s, height=%s"
+                          .format(x, y, width, height))
+        self.protocol.set_window_rect.set_window_rect(x, y, width, height)
+```
+
+Don't forget to write docs in ```testdriver.md```.
+Now we write the browser specific implementations.
+
+### Chrome
+
+We will use [executorwebdriver](https://github.com/web-platform-tests/wpt/blob/master/tools/wptrunner/wptrunner/executors/executorwebdriver.py) and use the WebDriver API.
+
+There isn't too much work to do here, we just need to define a subclass of the protocol part we defined earlier.
+
+```python
+class WebDriverSetWindowRectProtocolPart(SetWindowRectProtocolPart):
+    def setup(self):
+        self.webdriver = self.parent.webdriver
+
+    def set_window_rect(self, x, y, width, height):
+        return self.webdriver.set_window_rect(x, y, width, height)
+```
+
+Make sure to import the protocol part too!
+
+```python
+from .protocol import (BaseProtocolPart,
+                       TestharnessProtocolPart,
+                       Protocol,
+                       SelectorProtocolPart,
+                       ClickProtocolPart,
+                       SendKeysProtocolPart,
+                       {... other protocol parts}
+                       SetWindowRectProtocolPart, # add this!
+                       TestDriverProtocolPart)
+```
+
+Here we have the setup method which just redefines the webdriver object at this level. The important part is the `set_window_rect` function (and it's important it is named that since we called it that earlier). This will call the WebDriver API for [set window rect](https://w3c.github.io/webdriver/#set-window-rect).
+
+Finally, we just need to tell the WebDriverProtocol to implement this part.
+
+```python
+class WebDriverProtocol(Protocol):
+    implements = [WebDriverBaseProtocolPart,
+                  WebDriverTestharnessProtocolPart,
+                  WebDriverSelectorProtocolPart,
+                  WebDriverClickProtocolPart,
+                  WebDriverSendKeysProtocolPart,
+                  {... other protocol parts}
+                  WebDriverSetWindowRectProtocolPart, # add this!
+                  WebDriverTestDriverProtocolPart]
+```
+
+
+### Firefox
+We use the [set window rect](https://firefox-source-docs.mozilla.org/python/marionette_driver.html#marionette_driver.marionette.Marionette.set_window_rect) Marionette command.
+
+We will use [executormarionette](https://github.com/web-platform-tests/wpt/blob/master/tools/wptrunner/wptrunner/executors/executormarionette.py) and use the Marionette Python API.
+
+We have little actual work to do here! We just need to define a subclass of the protocol part we defined earlier.
+
+```python
+class MarionetteSetWindowRectProtocolPart(SetWindowRectProtocolPart):
+    def setup(self):
+        self.marionette = self.parent.marionette
+
+    def set_window_rect(self, x, y, width, height):
+        return self.marionette.set_window_rect(x, y, width, height)
+```
+
+Make sure to import the protocol part too!
+
+```python
+from .protocol import (BaseProtocolPart,
+                       TestharnessProtocolPart,
+                       Protocol,
+                       SelectorProtocolPart,
+                       ClickProtocolPart,
+                       SendKeysProtocolPart,
+                       {... other protocol parts}
+                       SetWindowRectProtocolPart, # add this!
+                       TestDriverProtocolPart)
+```
+
+Here we have the setup method which just redefines the webdriver object at this level. The important part is the `set_window_rect` function (and it's important it is named that since we called it that earlier). This will call the Marionette API for [set window rect](https://firefox-source-docs.mozilla.org/python/marionette_driver.html#marionette_driver.marionette.Marionette.set_window_rect) (`self.marionette` is a marionette instance here).
+
+Finally, we just need to tell the MarionetteProtocol to implement this part.
+
+```python
+class MarionetteProtocol(Protocol):
+    implements = [MarionetteBaseProtocolPart,
+                  MarionetteTestharnessProtocolPart,
+                  MarionettePrefsProtocolPart,
+                  MarionetteStorageProtocolPart,
+                  MarionetteSelectorProtocolPart,
+                  MarionetteClickProtocolPart,
+                  MarionetteSendKeysProtocolPart,
+                  {... other protocol parts}
+                  MarionetteSetWindowRectProtocolPart, # add this
+                  MarionetteTestDriverProtocolPart]
+```
+
+### Other Browsers
+
+Other browsers (such as safari) may use executorselenium, or a completely new executor (such as servo). For these, you must change the executor in the same way as we did with chrome and firefox.
+
+### Write an infra test
+
+Make sure to add a test to `infrastructure/testdriver` :)
+
+Here is some template code!
+
+```html
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver set window rect method</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<script>
+promise_test(async t => {
+  await test_driver.set_window_rect(100, 100, 100, 100);
+  // do something
+}
+</script>
+```
+### What about testdriver-vendor.js?
+
+The file [testdriver-vendor.js](https://github.com/web-platform-tests/wpt/blob/master/resources/testdriver-vendor.js) is the equivalent to testdriver-extra.js above, except it is
+run instead of testdriver-extra.js in browser-specific test environments. For example, in [Chromium web_tests](https://cs.chromium.org/chromium/src/third_party/blink/web_tests/).
+
+### What if I need to return a value from my testdriver API?
+
+You can return values from testdriver by just making your Action and Protocol classes use return statements. The data being returned will be serialized into JSON and passed
+back to the test on the resolving promise. The test can then deserialize the JSON to access the return values. Here is an example of a theoretical GetWindowRect API:
+
+```python
+class GetWindowRectAction(object):
+    def __call__(self, payload):
+        return self.protocol.get_window_rect.get_window_rect()
+```
+
+The WebDriver command will return a [WindowRect object](https://w3c.github.io/webdriver/#dfn-window-rect), which is a dictionary with keys `x`, `y`, `width`, and `height`.
+```python
+class WebDriverGetWindowRectProtocolPart(GetWindowRectProtocolPart):
+    def get_window_rect(self):
+        return self.webdriver.get_window_rect()
+```
+
+Then a test can access the return value as follows:
+```html
+<script>
+async_test(t => {
+  test_driver.get_window_rect()
+  .then((result) => {
+    assert_equals(result.x, 0)
+    assert_equals(result.y, 10)
+    assert_equals(result.width, 800)
+    assert_equals(result.height, 600)
+    t.done();
+  })
+});
+</script>
+```
+
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/testdriver.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/testdriver.md
new file mode 100644
index 0000000..63608a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/testdriver.md
@@ -0,0 +1,154 @@
+# testdriver.js Automation
+
+testdriver.js provides a means to automate tests that cannot be
+written purely using web platform APIs. Outside of automation
+contexts, it allows human operators to provide expected input
+manually (for operations which may be described in simple terms).
+
+It is currently supported only for [testharness.js](testharness)
+tests.
+
+## API
+
+testdriver.js exposes its API through the `test_driver` variable in
+the global scope.
+
+NB: presently, testdriver.js only works in the top-level test browsing
+context (and not therefore in any frame or window opened from it).
+
+### Actions
+Usage:
+```
+let actions = new test_driver.Actions()
+   .action1()
+   .action2();
+actions.send()
+```
+
+Test authors are encouraged to use the builder API to generate the sequence of actions. The builder
+API can be accessed via the `new test_driver.Actions()` object, and actions are defined in [testdriver-actions.js](https://github.com/web-platform-tests/wpt/blob/master/resources/testdriver-actions.js)
+
+The `actions.send()` function causes the sequence of actions to be sent to the browser. It is based on the [WebDriver API](https://w3c.github.io/webdriver/#actions).
+The action can be a keyboard action, a pointer action or a pause. It returns a promise that
+resolves after the actions have been sent, or rejects if an error was thrown.
+
+
+Example:
+
+```js
+let text_box = document.getElementById("text");
+
+let actions = new test_driver.Actions()
+    .pointerMove(0, 0, {origin: text_box})
+    .pointerDown()
+    .pointerUp()
+    .addTick()
+    .keyDown("p")
+    .keyUp("p");
+
+actions.send();
+```
+
+Calling into `send()` is going to dispatch the action sequence (via `test_driver.action_sequence`) and also returns a promise which should be handled however is appropriate in the test. The other functions in the `Actions()` object are going to modify the state of the object by adding a new action in the sequence and returning the same object. So the functions can be easily chained, as shown in the example above. Here is a list of helper functions in the `Actions` class:
+
+```
+pointerDown: Create a pointerDown event for the current default pointer source
+pointerUp: Create a pointerUp event for the current default pointer source
+pointerMove: Create a move event for the current default pointer source
+keyDown: Create a keyDown event for the current default key source
+keyUp: Create a keyUp event for the current default key source
+pause: Add a pause to the current tick
+addTick: Insert a new actions tick
+setPointer: Set the current default pointer source (By detault the pointerType is mouse)
+addPointer: Add a new pointer input source with the given name
+setKeyboard: Set the current default key source
+addKeyboard: Add a new key input source with the given name
+```
+
+### bless
+
+Usage: `test_driver.bless(intent, action)`
+ * _intent_: a string describing the motivation for this invocation
+ * _action_: an optional function
+
+This function simulates [activation][activation], allowing tests to
+perform privileged operations that require user interaction. For
+example, sandboxed iframes with
+`allow-top-navigation-by-user-activation` may only navigate their
+parent's browsing context under these circumstances. The _intent_
+string is presented to human operators when the test is not run in
+automation.
+
+This method returns a promise which is resolved with the result of
+invoking the _action_ function. If no such function is provided, the
+promise is resolved with the value `undefined`.
+
+Example:
+
+```js
+var mediaElement = document.createElement('video');
+
+test_driver.bless('initiate media playback', function () {
+  mediaElement.play();
+});
+```
+
+### click
+
+Usage: `test_driver.click(element)`
+ * _element_: a DOM Element object
+
+This function causes a click to occur on the target element (an
+`Element` object), potentially scrolling the document to make it
+possible to click it. It returns a promise that resolves after the
+click has occurred or rejects if the element cannot be clicked (for
+example, it is obscured by an element on top of it).
+
+Note that if the element to be clicked does not have a unique ID, the
+document must not have any DOM mutations made between the function
+being called and the promise settling.
+
+### send_keys
+
+Usage: `test_driver.send_keys(element, keys)`
+ * _element_: a DOM Element object
+ * _keys_: string to send to the element
+
+This function causes the string _keys_ to be sent to the target
+element (an `Element` object), potentially scrolling the document to
+make it possible to send keys. It returns a promise that resolves
+after the keys have been sent, or rejects if the keys cannot be sent
+to the element.
+
+Note that if the element that the keys need to be sent to does not have
+a unique ID, the document must not have any DOM mutations made
+between the function being called and the promise settling.
+
+To send special keys, one must send the respective key's codepoint. Since this uses the WebDriver protocol, you can find a [list for code points to special keys in the spec](https://w3c.github.io/webdriver/#keyboard-actions).
+For example, to send the tab key you would send "\uE004".
+
+[activation]: https://html.spec.whatwg.org/multipage/interaction.html#activation
+
+### set_permission
+
+Usage: `test_driver.set_permission(descriptor, state, one_realm)`
+ * _descriptor_: a
+   [PermissionDescriptor](https://w3c.github.io/permissions/#dictdef-permissiondescriptor)
+   or derived object
+ * _state_: a
+   [PermissionState](https://w3c.github.io/permissions/#enumdef-permissionstate)
+   value
+ * _one_realm_: a boolean that indicates whether the permission settings
+   apply to only one realm
+
+This function causes permission requests and queries for the status of a
+certain permission type (e.g. "push", or "background-fetch") to always
+return _state_. It returns a promise that resolves after the permission has
+been set to be overridden with _state_.
+
+Example:
+
+``` js
+await test_driver.set_permission({ name: "background-fetch" }, "denied");
+await test_driver.set_permission({ name: "push", userVisibleOnly: true }, "granted", true);
+```
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/testharness-api.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/testharness-api.md
new file mode 100644
index 0000000..8160ca2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/testharness-api.md
@@ -0,0 +1,938 @@
+# testharness.js API
+
+## Introduction ##
+
+testharness.js provides a framework for writing testcases. It is intended to
+provide a convenient API for making common assertions, and to work both
+for testing synchronous and asynchronous DOM features in a way that
+promotes clear, robust, tests.
+
+## Basic Usage ##
+
+The test harness script can be used from HTML or SVG documents and web worker
+scripts.
+
+From an HTML or SVG document, start by importing both `testharness.js` and
+`testharnessreport.js` scripts into the document:
+
+```html
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+```
+
+Refer to the [Web Workers](#web-workers) section for details and an example on
+testing within a web worker.
+
+Within each file one may define one or more tests. Each test is atomic in the
+sense that a single test has a single result (`PASS`/`FAIL`/`TIMEOUT`/`NOTRUN`).
+Within each test one may have a number of asserts. The test fails at the first
+failing assert, and the remainder of the test is (typically) not run.
+
+If the file containing the tests is a HTML file, a table containing the test
+results will be added to the document after all tests have run. By default this
+will be added to a `div` element with `id=log` if it exists, or a new `div`
+element appended to `document.body` if it does not.
+
+NOTE: By default tests must be created before the load event fires. For ways
+to create tests after the load event, see "Determining when all tests
+are complete", below.
+
+## Synchronous Tests ##
+
+To create a synchronous test use the `test()` function:
+
+```js
+test(test_function, name, properties)
+```
+
+`test_function` is a function that contains the code to test. For example a
+trivial test for the DOM
+[`hasFeature()`](https://dom.spec.whatwg.org/#dom-domimplementation-hasfeature)
+method (which is defined to always return true) would be:
+
+```js
+test(function() {
+  assert_true(document.implementation.hasFeature());
+}, "hasFeature() with no arguments")
+```
+
+The function passed in is run in the `test()` call.
+
+`properties` is a javascript object for passing extra options to the
+test. Currently it is only used to provide test-specific
+metadata, as described in the [metadata](#metadata) section below.
+
+## Asynchronous Tests ##
+
+Testing asynchronous features is somewhat more complex since the result of
+a test may depend on one or more events or other callbacks. The API provided
+for testing these features is intended to be rather low-level but hopefully
+applicable to many situations.
+
+To create a test, one starts by getting a `Test` object using `async_test`:
+
+```js
+async_test(name, properties)
+```
+
+e.g.
+
+```js
+var t = async_test("DOMContentLoaded")
+```
+
+Assertions can be added to the test by calling the step method of the test
+object with a function containing the test assertions:
+
+```js
+document.addEventListener("DOMContentLoaded", function() {
+  t.step(function() {
+    assert_true(e.bubbles, "bubbles should be true");
+  });
+});
+```
+
+When all the steps are complete, the `done()` method must be called:
+
+```js
+t.done();
+```
+
+As a convenience, `async_test` can also takes a function as first argument.
+This function is called with the test object as both its `this` object and
+first argument. The above example can be rewritten as:
+
+```js
+async_test(function(t) {
+  document.addEventListener("DOMContentLoaded", function() {
+    t.step(function() {
+      assert_true(e.bubbles, "bubbles should be true");
+    });
+    t.done();
+  });
+}, "DOMContentLoaded");
+```
+
+which avoids cluttering the global scope with references to async
+tests instances.
+
+The properties argument is identical to that for `test()`.
+
+In many cases it is convenient to run a step in response to an event or a
+callback. A convenient method of doing this is through the `step_func` method
+which returns a function that, when called runs a test step. For example:
+
+```js
+document.addEventListener("DOMContentLoaded", t.step_func(function() {
+  assert_true(e.bubbles, "bubbles should be true");
+  t.done();
+}));
+```
+
+As a further convenience, the `step_func` that calls `done()` can instead
+use `step_func_done`, as follows:
+
+```js
+document.addEventListener("DOMContentLoaded", t.step_func_done(function() {
+  assert_true(e.bubbles, "bubbles should be true");
+}));
+```
+
+For asynchronous callbacks that should never execute, `unreached_func` can
+be used. For example:
+
+```js
+document.documentElement.addEventListener("DOMContentLoaded",
+  t.unreached_func("DOMContentLoaded should not be fired on the document element"));
+```
+
+Keep in mind that other tests could start executing before an Asynchronous
+Test is finished.
+
+## Promise Tests ##
+
+`promise_test` can be used to test APIs that are based on Promises:
+
+```js
+promise_test(test_function, name, properties)
+```
+
+`test_function` is a function that receives a test as an argument. It must
+return a promise. The test completes when the returned promise settles. The
+test fails if the returned promise rejects.
+
+E.g.:
+
+```js
+function foo() {
+  return Promise.resolve("foo");
+}
+
+promise_test(function() {
+  return foo()
+    .then(function(result) {
+      assert_equals(result, "foo", "foo should return 'foo'");
+    });
+}, "Simple example");
+```
+
+In the example above, `foo()` returns a Promise that resolves with the string
+"foo". The `test_function` passed into `promise_test` invokes `foo` and attaches
+a resolve reaction that verifies the returned value.
+
+Note that in the promise chain constructed in `test_function`
+assertions don't need to be wrapped in `step` or `step_func`
+calls. However when mixing event handlers and `promise_test`, the
+event handler callback functions *do* need to be wrapped since an
+exception in these functions does not cause the promise chain to
+reject.
+
+Unlike Asynchronous Tests, Promise Tests don't start running until after the
+previous Promise Test finishes. [Under rare
+circumstances](https://github.com/web-platform-tests/wpt/pull/17924), the next
+test may begin to execute before the returned promise has settled. Use
+[add_cleanup](#cleanup) to register any necessary cleanup actions such as
+resetting global state that need to happen consistently before the next test
+starts.
+
+`promise_rejects_dom`, `promise_rejects_js`, and `promise_rejects_exactly` can
+be used to test Promises that need to reject:
+
+```js
+promise_rejects_dom(test_object, code, promise, description)
+promise_rejects_js(test_object, constructor, promise, description)
+promise_rejects_exactly(test_object, value, promise, description)
+```
+
+The `code`, `constructor`, and `value` arguments are equivalent to the same
+argument to the `assert_throws_dom`, `assert_throws_js`, and
+`assert_throws_exactly` functions.  The `promise_rejects_dom` function can also be called with a DOMException constructor argument between the `code` and `promise` arguments, just like `assert_throws_dom`, when we want to assert that the DOMException comes from a non-default global.
+
+Here's an example where the `bar()` function returns a Promise that rejects
+with a TypeError:
+
+```js
+function bar() {
+  return Promise.reject(new TypeError());
+}
+
+promise_test(function(t) {
+  return promise_rejects_js(t, TypeError, bar());
+}, "Another example");
+```
+
+## `EventWatcher` ##
+
+`EventWatcher` is a constructor function that allows DOM events to be handled
+using Promises, which can make it a lot easier to test a very specific series
+of events, including ensuring that unexpected events are not fired at any point.
+
+Here's an example of how to use `EventWatcher`:
+
+```js
+var t = async_test("Event order on animation start");
+
+var animation = watchedNode.getAnimations()[0];
+var eventWatcher = new EventWatcher(t, watchedNode, ['animationstart',
+                                                     'animationiteration',
+                                                     'animationend']);
+
+eventWatcher.wait_for('animationstart').then(t.step_func(function() {
+  assertExpectedStateAtStartOfAnimation();
+  animation.currentTime = END_TIME; // skip to end
+  // We expect two animationiteration events then an animationend event on
+  // skipping to the end of the animation.
+  return eventWatcher.wait_for(['animationiteration',
+                                'animationiteration',
+                                'animationend']);
+})).then(t.step_func(function() {
+  assertExpectedStateAtEndOfAnimation();
+  t.done();
+}));
+```
+
+`wait_for` either takes the name of a single event and returns a Promise that
+will resolve after that event is fired at the watched node, or else it takes an
+array of the names of a series of events and returns a Promise that will
+resolve after that specific series of events has been fired at the watched node.
+
+`EventWatcher` will assert if an event occurs while there is no `wait_for`()
+created Promise waiting to be fulfilled, or if the event is of a different type
+to the type currently expected. This ensures that only the events that are
+expected occur, in the correct order, and with the correct timing.
+
+## Single Page Tests ##
+
+Sometimes, particularly when dealing with asynchronous behaviour,
+having exactly one test per page is desirable, and the overhead of
+wrapping everything in functions for isolation becomes
+burdensome. For these cases `testharness.js` support "single page
+tests".
+
+In order for a test to be interpreted as a single page test, it should set the
+`single_test` [setup option](#setup) to `true`.
+
+```html
+<!doctype html>
+<title>Basic document.body test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+  <script>
+    setup({ single_test: true });
+    assert_equals(document.body, document.getElementsByTagName("body")[0])
+    done()
+ </script>
+```
+
+The test title for single page tests is always taken from `document.title`.
+
+## Making assertions ##
+
+Functions for making assertions start `assert_`. The full list of
+asserts available is documented in the [asserts](#list-of-assertions) section
+below. The general signature is:
+
+```js
+assert_something(actual, expected, description)
+```
+
+although not all assertions precisely match this pattern e.g. `assert_true`
+only takes `actual` and `description` as arguments.
+
+The description parameter is used to present more useful error messages when
+a test fails.
+
+When assertions are violated, they throw a runtime exception. This interrupts
+test execution, so subsequent statements are not evaluated. A given test can
+only fail due to one such violation, so if you would like to assert multiple
+behaviors independently, you should use multiple tests.
+
+NOTE: All asserts must be located in a `test()` or a step of an
+`async_test()`, unless the test is a single page test. Asserts outside
+these places won't be detected correctly by the harness and may cause
+unexpected exceptions that will lead to an error in the harness.
+
+## Optional Features ##
+
+If a test depends on a specification or specification feature that is OPTIONAL
+(in the [RFC 2119 sense](https://tools.ietf.org/html/rfc2119)),
+`assert_implements_optional` can be used to indicate that failing the test does
+not mean violating a web standard. For example:
+
+```js
+async_test((t) => {
+  const video = document.createElement("video");
+  assert_implements_optional(video.canPlayType("video/webm"));
+  video.src = "multitrack.webm";
+  // test something specific to multiple audio tracks in a WebM container
+  t.done();
+}, "WebM with multiple audio tracks");
+```
+
+A failing `assert_implements_optional` call is reported as a status of
+`PRECONDITION_FAILED` for the subtest. This unusual status code is a legacy
+leftover; see the [RFC that introduced
+`assert_implements_optional`](https://github.com/web-platform-tests/rfcs/pull/48).
+
+`assert_implements_optional` can also be used during test setup. For example:
+
+```js
+setup(() => {
+  assert_implements_optional("optionalfeature" in document.body,
+                             "'optionalfeature' event supported");
+});
+async_test(() => { /* test #1 waiting for "optionalfeature" event */ });
+async_test(() => { /* test #2 waiting for "optionalfeature" event */ });
+```
+
+A failing `assert_implements_optional` during setup is reported as a status of
+`PRECONDITION_FAILED` for the test, and the subtests will not run.
+
+See also the `.optional` [file name convention](file-names.md), which may be
+preferable if the entire test is optional.
+
+## Cleanup ##
+
+Occasionally tests may create state that will persist beyond the test itself.
+In order to ensure that tests are independent, such state should be cleaned
+up once the test has a result. This can be achieved by adding cleanup
+callbacks to the test. Such callbacks are registered using the `add_cleanup`
+function on the test object. All registered callbacks will be run as soon as
+the test result is known. For example:
+
+```js
+  test(function() {
+    var element = document.createElement("div");
+    element.setAttribute("id", "null");
+    document.body.appendChild(element);
+    this.add_cleanup(function() { document.body.removeChild(element) });
+    assert_equals(document.getElementById(null), element);
+  }, "Calling document.getElementById with a null argument.");
+```
+
+If the test was created using the `promise_test` API, then cleanup functions
+may optionally return a "thenable" value (i.e. an object which defines a `then`
+method). `testharness.js` will assume that such values conform to [the
+ECMAScript standard for
+Promises](https://tc39.github.io/ecma262/#sec-promise-objects) and delay the
+completion of the test until all "thenables" provided in this way have settled.
+All callbacks will be invoked synchronously; tests that require more complex
+cleanup behavior should manage execution order explicitly. If any of the
+eventual values are rejected, the test runner will report an error.
+
+## Timeouts in Tests ##
+
+In general the use of timeouts in tests is discouraged because this is
+an observed source of instability in real tests when run on CI
+infrastructure. In particular if a test should fail when something
+doesn't happen, it is good practice to simply let the test run to the
+full timeout rather than trying to guess an appropriate shorter
+timeout to use.
+
+In other cases it may be necessary to use a timeout (e.g., for a test
+that only passes if some event is *not* fired). In this case it is
+*not* permitted to use the standard `setTimeout` function. Instead one
+must use the `step_timeout` function:
+
+```js
+async_test(function(t) {
+  var gotEvent = false;
+  document.addEventListener("DOMContentLoaded", t.step_func(function() {
+    assert_false(gotEvent, "Unexpected DOMContentLoaded event");
+    gotEvent = true;
+    t.step_timeout(function() { t.done(); }, 2000);
+  });
+}, "Only one DOMContentLoaded");
+```
+
+The difference between `setTimeout` and `step_timeout` is that the
+latter takes account of the timeout multiplier when computing the
+delay; e.g., in the above case a timeout multiplier of 2 would cause a
+pause of 4000ms before calling the callback. This makes it less likely
+to produce unstable results in slow configurations.
+
+Note that timeouts generally need to be a few seconds long in order to
+produce stable results in all test environments.
+
+For single-page tests, `step_timeout` is also available as a global
+function.
+
+## Harness Timeout ##
+
+The overall harness admits two timeout values `"normal"` (the
+default) and `"long"`, used for tests which have an unusually long
+runtime. After the timeout is reached, the harness will stop
+waiting for further async tests to complete. By default the
+timeouts are set to 10s and 60s, respectively, but may be changed
+when the test is run on hardware with different performance
+characteristics to a common desktop computer.  In order to opt-in
+to the longer test timeout, the test must specify a meta element:
+
+```html
+<meta name="timeout" content="long">
+```
+
+Occasionally tests may have a race between the harness timing out and
+a particular test failing; typically when the test waits for some event
+that never occurs. In this case it is possible to use `test.force_timeout()`
+in place of `assert_unreached()`, to immediately fail the test but with a
+status of `TIMEOUT`. This should only be used as a last resort when it is
+not possible to make the test reliable in some other way.
+
+## Setup ##
+
+Sometimes tests require non-trivial setup that may fail. testharness.js
+provides two global functions for this purpose, `setup` and `promise_setup`.
+
+`setup()` may be called with one or two arguments. The two argument version is:
+
+```js
+setup(func, properties)
+```
+
+The one argument version may omit either argument. `func` is a function to be
+run synchronously. `setup()` becomes a no-op once any tests have returned
+results. `properties` is an object which specifies global properties of the
+test harness (enumerated in the following section).
+
+`promise_setup()` allows authors to pause testing until some asynchronous
+operation has completed. It has the following signature:
+
+```js
+promise_setup(func, properties)
+```
+
+Here, the `func` argument is required. This argument must be a function which
+returns an object with a `then` method (e.g. an ECMAScript Promise instance);
+the harness will wait for the fulfillment of this value before executing any
+additional subtests defined with the `promise_test` function. If the value is
+rejected, the harness will report an error and cancel the remaining tests.
+`properties` may optionally be provided as an object which specifies global
+properties of the test harness (enumerated in the following section).
+
+### Setup properties ##
+
+Both setup functions recognize the following properties:
+
+`explicit_done` - Wait for an explicit call to done() before declaring all
+tests complete (see below; implicitly true for single page tests)
+
+`output_document` - The document to which results should be logged. By default
+this is the current document but could be an ancestor document in some cases
+e.g. a SVG test loaded in an HTML wrapper
+
+`explicit_timeout` - disable file timeout; only stop waiting for results
+when the `timeout()` function is called (typically for use when integrating
+with some existing test framework that has its own timeout mechanism).
+
+`allow_uncaught_exception` - don't treat an uncaught exception as an error;
+needed when e.g. testing the `window.onerror` handler.
+
+`timeout_multiplier` - Multiplier to apply to per-test timeouts.
+
+`single_test` - Test authors may set this property to `true` to enable [the
+"single page test" mode of testharness.js](#single-page-tests); the current
+test must not declare any subtests; testharness.js will interpret all events
+which normally influence the harness status (e.g. uncaught exceptions,
+unhandled promise rejections, and timeouts) in terms of a single
+implicitly-defined subtest.
+
+## Determining when all tests are complete ##
+
+By default the test harness will assume there are no more results to come
+when:
+
+ 1. There are no `Test` objects that have been created but not completed
+ 2. The load event on the document has fired
+
+This behaviour can be overridden by setting the `explicit_done` property to
+true in a call to `setup()`. If `explicit_done` is true, the test harness will
+not assume it is done until the global `done()` function is called. Once `done()`
+is called, the two conditions above apply like normal.
+
+Dedicated and shared workers don't have an event that corresponds to the `load`
+event in a document. Therefore these worker tests always behave as if the
+`explicit_done` property is set to true (unless they are defined using [the
+"multi-global" pattern](testharness.html#multi-global-tests)). Service workers
+depend on the
+[install](https://w3c.github.io/ServiceWorker/#service-worker-global-scope-install-event)
+event which is fired following the completion of [running the
+worker](https://html.spec.whatwg.org/multipage/workers.html#run-a-worker).
+
+## **DEPRECATED** Generating tests ##
+
+There are scenarios in which is is desirable to create a large number of
+(synchronous) tests that are internally similar but vary in the parameters
+used. To make this easier, the `generate_tests` function allows a single
+function to be called with each set of parameters in a list:
+
+```js
+generate_tests(test_function, parameter_lists, properties)
+```
+
+For example:
+
+```js
+generate_tests(assert_equals, [
+    ["Sum one and one", 1+1, 2],
+    ["Sum one and zero", 1+0, 1]
+    ])
+```
+
+Is equivalent to:
+
+```js
+var a_got = 1+1;
+var a_exp = 2;
+var a_nam = "Sum one and one";
+var b_got = 1+0;
+var b_exp = 1;
+var b_nam = "Sum one and zero";
+test(function() {assert_equals(a_got, a_exp)}, a_nam);
+test(function() {assert_equals(b_got, b_exp)}, b_nam);
+```
+
+Note that the first item in each parameter list corresponds to the name of
+the test.
+
+The properties argument is identical to that for `test()`. This may be a
+single object (used for all generated tests) or an array.
+
+This is deprecated because it runs all the tests outside of the test functions
+and as a result any test throwing an exception will result in no tests being
+run. In almost all cases, you should simply call test within the loop you would
+use to generate the parameter list array.
+
+## Callback API ##
+
+The framework provides callbacks corresponding to 4 events:
+
+ * `start` - triggered when the first Test is created
+ * `test_state` - triggered when a test state changes
+ * `result` - triggered when a test result is received
+ * `complete` - triggered when all results are received
+
+The page defining the tests may add callbacks for these events by calling
+the following methods:
+
+  `add_start_callback(callback)` - callback called with no arguments
+
+  `add_test_state_callback(callback)` - callback called with a test argument
+
+  `add_result_callback(callback)` - callback called with a test argument
+
+  `add_completion_callback(callback)` - callback called with an array of tests
+                                        and a status object
+
+Tests have the following properties:
+
+  * `status` - A status code. This can be compared to the `PASS`, `FAIL`,
+               `PRECONDITION_FAILED`, `TIMEOUT` and `NOTRUN` properties on the
+               test object
+
+  * `message` - A message indicating the reason for failure. In the future this
+                will always be a string
+
+ The status object gives the overall status of the harness. It has the
+ following properties:
+
+ * `status` - Can be compared to the `OK`, `PRECONDITION_FAILED`, `ERROR` and
+              `TIMEOUT` properties
+
+ * `message` - An error message set when the status is `PRECONDITION_FAILED`
+               or `ERROR`.
+
+## External API ##
+
+In order to collect the results of multiple pages containing tests, the test
+harness will, when loaded in a nested browsing context, attempt to call
+certain functions in each ancestor and opener browsing context:
+
+ * start - `start_callback`
+ * test\_state - `test_state_callback`
+ * result - `result_callback`
+ * complete - `completion_callback`
+
+These are given the same arguments as the corresponding internal callbacks
+described above.
+
+## External API through cross-document messaging ##
+
+Where supported, the test harness will also send messages using cross-document
+messaging to each ancestor and opener browsing context. Since it uses the
+wildcard keyword (\*), cross-origin communication is enabled and script on
+different origins can collect the results.
+
+This API follows similar conventions as those described above only slightly
+modified to accommodate message event API. Each message is sent by the harness
+is passed a single vanilla object, available as the `data` property of the event
+object. These objects are structured as follows:
+
+ * start - `{ type: "start" }`
+ * test\_state - `{ type: "test_state", test: Test }`
+ * result - `{ type: "result", test: Test }`
+ * complete - `{ type: "complete", tests: [Test, ...], status: TestsStatus }`
+
+## Consolidating tests from other documents ##
+
+`fetch_tests_from_window` will aggregate tests from separate windows or iframes
+into the current document as if they were all part of the same test suite. The
+document of the second window (or iframe) should include `testharness.js`, but
+not `testharnessreport.js`, and use `test`, `async_test`, and `promise_test` in
+the usual manner.
+
+The current test suite will not report completion until
+all fetched tests are complete, and errors in the child contexts will result in
+failures for the suite in the current context.
+
+Here's an example that uses `window.open`.
+
+`child.html`:
+
+```html
+<!DOCTYPE html>
+<html>
+<title>Child context test(s)</title>
+<head>
+  <script src="/resources/testharness.js"></script>
+</head>
+<body>
+  <div id="log"></div>
+  <script>
+    test(function(t) {
+      assert_true(true, "true is true");
+    }, "Simple test");
+  </script>
+</body>
+</html>
+```
+
+`test.html`:
+
+```html
+<!DOCTYPE html>
+<html>
+<title>Primary test context</title>
+<head>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+  <div id="log"></div>
+  <script>
+    var child_window = window.open("child.html");
+    fetch_tests_from_window(child_window);
+  </script>
+</body>
+</html>
+```
+
+The argument to `fetch_tests_from_window` is any [`Window`](https://html.spec.whatwg.org/multipage/browsers.html#the-window-object)
+capable of accessing the browsing context as either an ancestor or opener.
+
+## Web Workers ##
+
+The `testharness.js` script can be used from within [dedicated workers, shared
+workers](https://html.spec.whatwg.org/multipage/workers.html) and [service
+workers](https://w3c.github.io/ServiceWorker/).
+
+Testing from a worker script is different from testing from an HTML document in
+several ways:
+
+* Workers have no reporting capability since they are running in the background.
+  Hence they rely on `testharness.js` running in a companion client HTML document
+  for reporting.
+
+* Shared and service workers do not have a unique client document since there
+  could be more than one document that communicates with these workers. So a
+  client document needs to explicitly connect to a worker and fetch test results
+  from it using `fetch_tests_from_worker`. This is true even for a dedicated
+  worker. Once connected, the individual tests running in the worker (or those
+  that have already run to completion) will be automatically reflected in the
+  client document.
+
+* The client document controls the timeout of the tests. All worker scripts act
+  as if they were started with the `explicit_timeout` option (see the [Harness
+  timeout](#harness-timeout) section).
+
+* Dedicated and shared workers don't have an equivalent of an `onload` event.
+  Thus the test harness has no way to know when all tests have completed (see
+  [Determining when all tests are
+  complete](#determining-when-all-tests-are-complete)). So these worker tests
+  behave as if they were started with the `explicit_done` option. Service
+  workers depend on the
+  [oninstall](https://w3c.github.io/ServiceWorker/#service-worker-global-scope-install-event)
+  event and don't require an explicit `done` call.
+
+Here's an example that uses a dedicated worker.
+
+`worker.js`:
+
+```js
+importScripts("/resources/testharness.js");
+
+test(function(t) {
+  assert_true(true, "true is true");
+}, "Simple test");
+
+// done() is needed because the testharness is running as if explicit_done
+// was specified.
+done();
+```
+
+`test.html`:
+
+```html
+<!DOCTYPE html>
+<title>Simple test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+
+fetch_tests_from_worker(new Worker("worker.js"));
+
+</script>
+```
+
+The argument to the `fetch_tests_from_worker` function can be a
+[`Worker`](https://html.spec.whatwg.org/multipage/workers.html#dedicated-workers-and-the-worker-interface),
+a [`SharedWorker`](https://html.spec.whatwg.org/multipage/workers.html#shared-workers-and-the-sharedworker-interface)
+or a [`ServiceWorker`](https://w3c.github.io/ServiceWorker/#serviceworker-interface).
+Once called, the containing document fetches all the tests from the worker and
+behaves as if those tests were running in the containing document itself.
+
+`fetch_tests_from_worker` returns a promise that resolves once all the remote
+tests have completed. This is useful if you're importing tests from multiple
+workers and want to ensure they run in series:
+
+```js
+(async function() {
+  await fetch_tests_from_worker(new Worker("worker-1.js"));
+  await fetch_tests_from_worker(new Worker("worker-2.js"));
+})();
+```
+
+## List of Assertions ##
+
+### `assert_true(actual, description)`
+asserts that `actual` is strictly true
+
+### `assert_false(actual, description)`
+asserts that `actual` is strictly false
+
+### `assert_equals(actual, expected, description)`
+asserts that `actual` is the same value as `expected`.
+Relies on `===`, distinguishes between `-0` and `+0`, and has a specific check for `NaN`.
+
+### `assert_not_equals(actual, expected, description)`
+asserts that `actual` is a different value to `expected`.
+This means that `expected` is a misnomer.
+Relies on `===`, distinguishes between `-0` and `+0`, and has a specific check for `NaN`.
+
+### `assert_in_array(actual, expected, description)`
+asserts that `expected` is an Array, and `actual` is equal to one of the
+members i.e. `expected.indexOf(actual) != -1`
+
+### `assert_object_equals(actual, expected, description)`
+asserts that `actual` is an object and not null and that all enumerable
+properties on `actual` are own properties on `expected` with the same values,
+recursing if the value is an object and not null.
+
+### `assert_array_equals(actual, expected, description)`
+asserts that `actual` and `expected` have the same
+length and the value of each indexed property in `actual` is the strictly equal
+to the corresponding property value in `expected`
+
+### `assert_array_approx_equals(actual, expected, epsilon, description)`
+asserts that `actual` and `expected` have the same
+length and each indexed property in `actual` is a number
+within ±`epsilon` of the corresponding property in `expected`
+
+### `assert_approx_equals(actual, expected, epsilon, description)`
+asserts that `actual` is a number within ±`epsilon` of `expected`
+
+### `assert_less_than(actual, expected, description)`
+asserts that `actual` is a number less than `expected`
+
+### `assert_greater_than(actual, expected, description)`
+asserts that `actual` is a number greater than `expected`
+
+### `assert_between_exclusive(actual, lower, upper, description`
+asserts that `actual` is a number between `lower` and `upper` but not
+equal to either of them
+
+### `assert_less_than_equal(actual, expected, description)`
+asserts that `actual` is a number less than or equal to `expected`
+
+### `assert_greater_than_equal(actual, expected, description)`
+asserts that `actual` is a number greater than or equal to `expected`
+
+### `assert_between_inclusive(actual, lower, upper, description`
+asserts that `actual` is a number between `lower` and `upper` or
+equal to either of them
+
+### `assert_regexp_match(actual, expected, description)`
+asserts that `actual` matches the regexp `expected`
+
+### `assert_class_string(object, class_name, description)`
+asserts that the class string of `object` as returned in
+`Object.prototype.toString` is equal to `class_name`.
+
+### `assert_own_property(object, property_name, description)`
+assert that object has own property `property_name`
+
+### `assert_not_own_property(object, property_name, description)`
+assert that object does not have an own property named `property_name`
+
+### `assert_inherits(object, property_name, description)`
+assert that object does not have an own property named
+`property_name` but that `property_name` is present in the prototype
+chain for object
+
+### `assert_idl_attribute(object, attribute_name, description)`
+assert that an object that is an instance of some interface has the
+attribute attribute_name following the conditions specified by WebIDL
+
+### `assert_readonly(object, property_name, description)`
+assert that property `property_name` on object is readonly
+
+### `assert_throws_dom(code, func, description)` or `assert_throws_dom(code, constructor, func, description)`
+`code` - the expected exception. This can take several forms:
+
+  * string - asserts that the thrown exception must be a DOMException
+             with the given name, e.g., "TimeoutError". (For
+             compatibility with existing tests, the name of a
+             DOMException constant can also be given, e.g.,
+             "TIMEOUT_ERR")
+  * number - asserts that the thrown exception must be a DOMException
+             with the fiven code value (e.g. DOMException.TIMEOUT_ERR).
+
+`func` - a function that should throw
+
+`constructor` - The DOMException constructor that the resulting DOMException should have as its `.constructor`.  This should be used when a DOMException from a non-default global is expected to be thrown.
+
+### `assert_throws_js(constructor, func, description)`
+`constructor` - the expected exception. This is the constructor object
+that the exception should have as its .constructor.  For example,
+`TypeError` or `someOtherWindow.RangeError`.
+
+`func` - a function that should throw
+
+### `assert_throws_exactly(value, func, description)`
+`value` - the exact value that `func` is expected to throw if called.
+
+`func` - a function that should throw
+
+### `assert_implements(condition, description)`
+asserts that a feature is supported, by checking if `condition` is truthy.
+
+### `assert_implements_optional(condition, description)`
+asserts that an optional feature is supported, by checking if `condition` is truthy.
+See [Optional Features](#optional-features) for usage.
+
+### `assert_unreached(description)`
+asserts if called. Used to ensure that some codepath is *not* taken e.g.
+an event does not fire.
+
+### `assert_any(assert_func, actual, expected_array, extra_arg_1, ... extra_arg_N)`
+asserts that one `assert_func(actual, expected_array_N, extra_arg1, ..., extra_arg_N)`
+  is true for some `expected_array_N` in `expected_array`. This only works for `assert_func`
+  with signature `assert_func(actual, expected, args_1, ..., args_N)`. Note that tests
+  with multiple allowed pass conditions are bad practice unless the spec specifically
+  allows multiple behaviours. Test authors should not use this method simply to hide
+  UA bugs.
+
+## Utility functions ##
+
+### **DEPRECATED** `on_event(object, event, callback)`
+
+Register a function as a DOM event listener to the given object for the event
+bubbling phase. New tests should not use this function. Instead, they should
+invoke the `addEventListener` method of the `object` value.
+
+### `format_value(value)`
+
+When many JavaScript Object values are coerced to a String, the resulting value
+will be `"[object Object]"`. This obscures helpful information, making the
+coerced value unsuitable for use in assertion messages, test names, and
+debugging statements.
+
+testharness.js provides a global function named `format_value` which produces
+more distinctive string representations of many kinds of objects, including
+arrays and the more important DOM Node types. It also translates String values
+containing control characters to include human-readable representations.
+
+```js
+format_value(document); // "Document node with 2 children"
+format_value("foo\uffffbar"); // "\"foo\\uffffbar\""
+format_value([-0, Infinity]); // "[-0, Infinity]"
+```
+
+## Metadata ##
+
+It is possible to add optional metadata to tests; this can be done in
+one of two ways; either by adding `<meta>` elements to the head of the
+document containing the tests, or by adding the metadata to individual
+`[async_]test` calls, as properties.
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/testharness-tutorial.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/testharness-tutorial.md
new file mode 100644
index 0000000..dceb674
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/testharness-tutorial.md
@@ -0,0 +1,393 @@
+# testharness.js tutorial
+
+<!--
+Note to maintainers:
+
+This tutorial is designed to be an authentic depiction of the WPT contribution
+experience. It is not intended to be comprehensive; its scope is intentionally
+limited in order to demonstrate authoring a complete test without overwhelming
+the reader with features. Because typical WPT usage patterns change over time,
+this should be updated periodically; please weigh extensions against the
+demotivating effect that a lengthy guide can have on new contributors.
+-->
+
+Let's say you've discovered that WPT doesn't have any tests for how [the Fetch
+API](https://fetch.spec.whatwg.org/) sets cookies from an HTTP response. This
+tutorial will guide you through the process of writing a test for the
+web-platform, verifying it, and submitting it back to WPT. Although it includes
+some very brief instructions on using git, you can find more guidance in [the
+tutorial for git and GitHub](github-intro).
+
+WPT's testharness.js is a framework designed to help people write tests for the
+web platform's JavaScript APIs. [The testharness.js reference
+page](testharness) describes the framework in the abstract, but for the
+purposes of this guide, we'll only consider the features we need to test the
+behavior of `fetch`.
+
+```eval_rst
+.. contents::
+   :local:
+```
+
+## Setting up your workspace
+
+To make sure you have the latest code, first type the following into a terminal
+located in the root of the WPT git repository:
+
+    $ git fetch git@github.com:web-platform-tests/wpt.git
+
+Next, we need a place to store the change set we're about to author. Here's how
+to create a new git branch named `fetch-cookie` from the revision of WPT we
+just downloaded:
+
+    $ git checkout -b fetch-cookie FETCH_HEAD
+
+The tests we're going to write will rely on special abilities of the WPT
+server, so you'll also need to [configure your system to run
+WPT](../running-tests/from-local-system) before you continue.
+
+With that out of the way, you're ready to create your patch.
+
+## Writing a subtest
+
+<!--
+Goals of this section:
+
+- demonstrate asynchronous testing with Promises
+- motivate non-trivial integration with WPT server
+- use web technology likely to be familiar to web developers
+- use web technology likely to be supported in the reader's browser
+-->
+
+The first thing we'll do is configure the server to respond to a certain request
+by setting a cookie. Once that's done, we'll be able to make the request with
+`fetch` and verify that it interpreted the response correctly.
+
+We'll configure the server with an "asis" file. That's the WPT convention for
+controlling the contents of an HTTP response. [You can read more about it
+here](server-features), but for now, we'll save the following text into a file
+named `set-cookie.asis` in the `fetch/api/basic/` directory of WPT:
+
+```
+HTTP/1.1 204 No Content
+Set-Cookie: test1=t1
+```
+
+With this in place, any requests to `/fetch/api/basic/set-cookie.asis` will
+receive an HTTP 204 response that sets the cookie named `test1`. When writing
+more tests in the future, you may want the server to behave more dynamically.
+In that case, [you can write Python code to control how the server
+responds](python-handlers/index).
+
+Now, we can write the test! Create a new file named `set-cookie.html` in the
+same directory and insert the following text:
+
+```html
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>fetch: setting cookies</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+promise_test(function() {
+  return fetch('set-cookie.asis')
+    .then(function() {
+        assert_equals(document.cookie, 'test1=t1');
+      });
+});
+</script>
+```
+
+Let's step through each part of this file.
+
+- ```html
+  <!DOCTYPE html>
+  <meta charset="utf-8">
+  ```
+
+  We explicitly set the DOCTYPE and character set to be sure that browsers
+  don't infer them to be something we aren't expecting. We're omitting the
+  `<html>` and `<head>` tags. That's a common practice in WPT, preferred
+  because it makes tests more concise.
+
+- ```html
+  <title>fetch: setting cookies</title>
+  ```
+  The document's title should succinctly describe the feature under test.
+
+- ```html
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  ```
+
+  These two `<script>` tags retrieve the code that powers testharness.js. A
+  testharness.js test can't run without them!
+
+- ```html
+  <script>
+  promise_test(function() {
+    return fetch('thing.asis')
+      .then(function() {
+          assert_equals(document.cookie, 'test1=t1');
+        });
+  });
+  </script>
+  ```
+
+  This script uses the testharness.js function `promise_test` to define a
+  "subtest". We're using that because the behavior we're testing is
+  asynchronous. By returning a Promise value, we tell the harness to wait until
+  that Promise settles. The harness will report that the test has passed if
+  the Promise is fulfilled, and it will report that the test has failed if the
+  Promise is rejected.
+
+  We invoke the global `fetch` function to exercise the "behavior under test,"
+  and in the fulfillment handler, we verify that the expected cookie is set.
+  We're using the testharness.js `assert_equals` function to verify that the
+  value is correct; the function will throw an error otherwise. That will cause
+  the Promise to be rejected, and *that* will cause the harness to report a
+  failure.
+
+If you run the server according to the instructions in [the guide for local
+configuration](../running-tests/from-local-system), you can access the test at
+[http://web-platform.test:8000/fetch/api/basic/set-cookie.html](http://web-platform.test:8000/fetch/api/basic/set-cookie.html.).
+You should see something like this:
+
+![](../assets/testharness-tutorial-test-screenshot-1.png "screen shot of testharness.js reporting the test results")
+
+## Refining the subtest
+
+<!--
+Goals of this section:
+
+- explain the motivation for "clean up" logic and demonstrate its usage
+- motivate explicit test naming
+-->
+
+We'd like to test a little more about `fetch` and cookies, but before we do,
+there are some improvements we can make to what we've written so far.
+
+For instance, we should remove the cookie after the subtest is complete. This
+ensures a consistent state for any additional subtests we may add and also for
+any tests that follow. We'll use the `add_cleanup` method to ensure that the
+cookie is deleted even if the test fails.
+
+```diff
+-promise_test(function() {
++promise_test(function(t) {
++  t.add_cleanup(function() {
++    document.cookie = 'test1=;expires=Thu, 01 Jan 1970 00:00:01 GMT;';
++  });
++
+   return fetch('thing.asis')
+     .then(function() {
+         assert_equals(document.cookie, 'test1=t1');
+       });
+ });
+```
+
+Although we'd prefer it if there were no other cookies defined during our test,
+we shouldn't take that for granted. As written, the test will fail if the
+`document.cookie` includes additional cookies. We'll use slightly more
+complicated logic to test for the presence of the expected cookie.
+
+
+```diff
+ promise_test(function(t) {
+   t.add_cleanup(function() {
+     document.cookie = 'test1=;expires=Thu, 01 Jan 1970 00:00:01 GMT;';
+   });
+
+   return fetch('thing.asis')
+     .then(function() {
+-        assert_equals(document.cookie, 'test1=t1');
++        assert_true(/(^|; )test1=t1($|;)/.test(document.cookie);
+       });
+ });
+```
+
+In the screen shot above, the subtest's result was reported using the
+document's title, "fetch: setting cookies". Since we expect to add another
+subtest, we should give this one a more specific name:
+
+```diff
+ promise_test(function(t) {
+   t.add_cleanup(function() {
+     document.cookie = 'test1=;expires=Thu, 01 Jan 1970 00:00:01 GMT;';
+   });
+
+   return fetch('thing.asis')
+     .then(function() {
+         assert_true(/(^|; )test1=t1($|;)/.test(document.cookie));
+       });
+-});
++}, 'cookie set for successful request');
+```
+
+## Writing a second subtest
+
+<!--
+Goals of this section:
+
+- introduce the concept of cross-domain testing and the associated tooling
+- demonstrate how to verify promise rejection
+- demonstrate additional assertion functions
+-->
+
+There are many things we might want to verify about how `fetch` sets cookies.
+For instance, it should *not* set a cookie if the request fails due to
+cross-origin security restrictions. Let's write a subtest which verifies that.
+
+We'll add another `<script>` tag for a JavaScript support file:
+
+```diff
+ <!DOCTYPE html>
+ <meta charset="utf-8">
+ <title>fetch: setting cookies</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
++<script src="/common/get-host-info.sub.js"></script>
+```
+
+`get-host-info.sub.js` is a general-purpose script provided by WPT. It's
+designed to help with testing cross-domain functionality. Since it's stored in
+WPT's `common/` directory, tests from all sorts of specifications rely on it.
+
+Next, we'll define the new subtest inside the same `<script>` tag that holds
+our first subtest.
+
+```js
+promise_test(function(t) {
+  t.add_cleanup(function() {
+    document.cookie = 'test1=;expires=Thu, 01 Jan 1970 00:00:01 GMT;';
+  });
+  const url = get_host_info().HTTP_NOTSAMESITE_ORIGIN +
+    '/fetch/api/basic/set-cookie.asis';
+
+  return fetch(url)
+    .then(function() {
+        assert_unreached('The promise for the aborted fetch operation should reject.');
+      }, function() {
+        assert_false(/(^|; )test1=t1($|;)/.test(document.cookie));
+      });
+}, 'no cookie is set for cross-domain fetch operations');
+```
+
+This may look familiar from the previous subtest, but there are some important
+differences.
+
+- ```js
+  const url = get_host_info().HTTP_NOTSAMESITE_ORIGIN +
+    '/fetch/api/basic/set-cookie.asis';
+  ```
+
+  We're requesting the same resource, but we're referring to it with an
+  alternate host name. The name of the host depends on how the WPT server has
+  been configured, so we rely on the helper to provide an appropriate value.
+
+- ```js
+  return fetch(url)
+    .then(function() {
+        assert_unreached('The promise for the aborted fetch operation should reject.');
+      }, function() {
+        assert_false(/(^|; )test1=t1($|;)/.test(document.cookie));
+      });
+  ```
+
+  We're returning a Promise value, just like the first subtest. This time, we
+  expect the operation to fail, so the Promise should be rejected. To express
+  this, we've used `assert_unreached` *in the fulfillment handler*.
+  `assert_unreached` is a testharness.js utility function which always throws
+  an error. With this in place, if fetch does *not* produce an error, then this
+  subtest will fail.
+
+  We've moved the assertion about the cookie to the rejection handler. We also
+  switched from `assert_true` to `assert_false` because the test should only
+  pass if the cookie is *not* set. It's a good thing we have the cleanup logic
+  in the previous subtest, right?
+
+If you run the test in your browser now, you can expect to see both tests
+reported as passing with their distinct names.
+
+![](../assets/testharness-tutorial-test-screenshot-2.png "screen shot of testharness.js reporting the test results")
+
+## Verifying our work
+
+We're done writing the test, but we should make sure it fits in with the rest
+of WPT before we submit it.
+
+[The lint tool](lint-tool) can detect some of the common mistakes people make
+when contributing to WPT. You enabled it when you [configured your system to
+work with WPT](../running-tests/from-local-system). To run it, open a
+command-line terminal, navigate to the root of the WPT repository, and enter
+the following command:
+
+    python ./wpt lint fetch/api/basic
+
+If this recognizes any of those common mistakes in the new files, it will tell
+you where they are and how to fix them. If you do have changes to make, you can
+run the command again to make sure you got them right.
+
+Now, we'll run the test using the automated test runner. This is important for
+testharness.js tests because there are subtleties of the automated test runner
+which can influence how the test behaves. That's not to say your test has to
+pass in all browsers (or even in *any* browser). But if we expect the test to
+pass, then running it this way will help us catch other kinds of mistakes.
+
+The tools support running the tests in many different browsers. We'll use
+Firefox this time:
+
+    python ./wpt run firefox fetch/api/basic/set-cookie.html
+
+We expect this test to pass, so if it does, we're ready to submit it. If we
+were testing a web-platform feature that Firefox didn't support, we would
+expect the test to fail instead.
+
+There are a few problems to look out for in addition to passing/failing status.
+The report will describe fewer tests than we expect if the test isn't run at
+all. That's usually a sign of a formatting mistake, so you'll want to make sure
+you've used the right file names and metadata. Separately, the web browser
+might crash. That's often a sign of a browser bug, so you should consider
+[reporting it to the browser's
+maintainers](https://rachelandrew.co.uk/archives/2017/01/30/reporting-browser-bugs/)!
+
+## Submitting the test
+
+First, let's stage the new files for committing:
+
+    $ git add fetch/api/basic/set-cookie.asis
+    $ git add fetch/api/basic/set-cookie.html
+
+We can make sure the commit has everything we want to submit (and nothing we
+don't) by using `git diff`:
+
+    $ git diff --staged
+
+On most systems, you can use the arrow keys to navigate through the changes,
+and you can press the `q` key when you're done reviewing.
+
+Next, we'll create a commit with the staged changes:
+
+    $ git commit -m '[fetch] Add test for setting cookies'
+
+And now we can push the commit to our fork of WPT:
+
+    $ git push origin fetch-cookie
+
+The last step is to submit the test for review. WPT doesn't actually need the
+test we wrote in this tutorial, but if we wanted to submit it for inclusion in
+the repository, we would create a pull request on GitHub. [The guide on git and
+GitHub](github-intro) has all the details on how to do that.
+
+## More practice
+
+Here are some ways you can keep experimenting with WPT using this test:
+
+- Improve the test's readability by defining helper functions like
+  `cookieIsSet` and `deleteCookie`
+- Improve the test's coverage by refactoring it into [a "multi-global"
+  test](testharness)
+- Improve the test's coverage by writing more subtests (e.g. the behavior when
+  the fetch operation is aborted by `window.stop`, or the behavior when the
+  HTTP response sets multiple cookies)
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/testharness.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/testharness.md
new file mode 100644
index 0000000..1e9772a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/testharness.md
@@ -0,0 +1,212 @@
+# testharness.js Tests
+
+```eval_rst
+.. toctree::
+   :maxdepth: 1
+
+   idlharness
+   testharness-api
+   testdriver-extension-tutorial
+   testdriver
+```
+
+testharness.js tests are the correct type of test to write in any
+situation where you are not specifically interested in the rendering
+of a page, and where human interaction isn't required; these tests are
+written in JavaScript using a framework called `testharness.js`. It is
+documented in two sections:
+
+  * [testharness.js Documentation](testharness-api.md) — An introduction
+    to the library and a detailed API reference.
+
+  * [idlharness.js Documentation](idlharness.md) — A library for testing
+     IDL interfaces using `testharness.js`.
+
+See [server features](server-features.md) for advanced testing features that are commonly used
+with testharness.js. See also the [general guidelines](general-guidelines.md) for all test types.
+
+This page describes testharness.js exhaustively; [the tutorial on writing a
+testharness.js test](testharness-tutorial) provides a concise guide to writing
+a test--a good place to start for newcomers to the project.
+
+## Variants
+
+A test file can have multiple variants by including `meta` elements,
+for example:
+
+```html
+<meta name="variant" content="">
+<meta name="variant" content="?wss">
+```
+
+The test can then do different things based on the URL.
+
+There are two utility scripts in that work well together with variants,
+`/common/subset-tests.js` and `/common/subset-tests-by-key.js`, where
+a test that would otherwise have too many tests to be useful can be
+split up in ranges of subtests. For example:
+
+```html
+<!doctype html>
+<title>Testing variants</title>
+<meta name="variant" content="?1-1000">
+<meta name="variant" content="?1001-2000">
+<meta name="variant" content="?2001-last">
+<script src="/resources/testharness.js">
+<script src="/resources/testharnessreport.js">
+<script src="/common/subset-tests.js">
+<script>
+ const tests = [
+                 { fn: t => { ... }, name: "..." },
+                 ... lots of tests ...
+               ];
+ for (const test of tests) {
+   subsetTest(async_test, test.fn, test.name);
+ }
+</script>
+```
+
+With `subsetTestByKey`, the key is given as the first argument, and the
+query string can include or exclude a key (will be matched as a regular
+expression).
+
+```html
+<!doctype html>
+<title>Testing variants by key</title>
+<meta name="variant" content="?include=Foo">
+<meta name="variant" content="?include=Bar">
+<meta name="variant" content="?exclude=(Foo|Bar)">
+<script src="/resources/testharness.js">
+<script src="/resources/testharnessreport.js">
+<script src="/common/subset-tests-by-key.js">
+<script>
+   subsetTestByKey("Foo", async_test, () => { ... }, "Testing foo");
+   ...
+</script>
+```
+
+## Auto-generated test boilerplate
+
+While most JavaScript tests require a certain amount of HTML
+boilerplate to include the test library, etc., tests which are
+expressible purely in script (e.g. tests for workers) can have all the
+needed HTML and script boilerplate auto-generated.
+
+### Standalone window tests
+
+Tests that only require a script file running in window scope can use
+standalone window tests. In this case the test is a javascript file
+with the extension `.window.js`. This is sourced from a generated
+document which sources `testharness.js`, `testharnessreport.js` and
+the test script. For a source script with the name
+`example.window.js`, the corresponding test resource will be
+`example.window.html`.
+
+### Standalone workers tests
+
+Tests that only require assertions in a dedicated worker scope can use
+standalone workers tests. In this case, the test is a JavaScript file
+with extension `.worker.js` that imports `testharness.js`. The test can
+then use all the usual APIs, and can be run from the path to the
+JavaScript file with the `.js` removed.
+
+For example, one could write a test for the `FileReaderSync` API by
+creating a `FileAPI/FileReaderSync.worker.js` as follows:
+
+```js
+importScripts("/resources/testharness.js");
+test(function () {
+    const blob = new Blob(["Hello"]);
+    const fr = new FileReaderSync();
+    assert_equals(fr.readAsText(blob), "Hello");
+}, "FileReaderSync#readAsText.");
+done();
+```
+
+This test could then be run from `FileAPI/FileReaderSync.worker.html`.
+
+### Multi-global tests
+
+Tests for features that exist in multiple global scopes can be written in a way
+that they are automatically run in several scopes. In this case, the test is a
+JavaScript file with extension `.any.js`, which can use all the usual APIs.
+
+By default, the test runs in a window scope and a dedicated worker scope.
+
+For example, one could write a test for the `Blob` constructor by
+creating a `FileAPI/Blob-constructor.any.js` as follows:
+
+```js
+test(function () {
+    const blob = new Blob();
+    assert_equals(blob.size, 0);
+    assert_equals(blob.type, "");
+    assert_false(blob.isClosed);
+}, "The Blob constructor.");
+```
+
+This test could then be run from `FileAPI/Blob-constructor.any.worker.html` as well
+as `FileAPI/Blob-constructor.any.html`.
+
+It is possible to customize the set of scopes with a metadata comment, such as
+
+```
+// META: global=sharedworker
+//       ==> would run in the shared worker scope
+// META: global=window,serviceworker
+//       ==> would only run in the window and service worker scope
+// META: global=dedicatedworker
+//       ==> would run in the default dedicated worker scope
+// META: global=worker
+//       ==> would run in the dedicated, shared, and service worker scopes
+```
+
+For a test file <code><var>x</var>.any.js</code>, the available scope keywords
+are:
+
+* `window` (default): to be run at <code><var>x</var>.any.html</code>
+* `dedicatedworker` (default): to be run at <code><var>x</var>.any.worker.html</code>
+* `serviceworker`: to be run at <code><var>x</var>.any.serviceworker.html</code> (`.https` is implied)
+* `sharedworker`: to be run at <code><var>x</var>.any.sharedworker.html</code>
+* `jsshell`: to be run in a JavaScript shell, without access to the DOM
+  (currently only supported in SpiderMonkey, and skipped in wptrunner)
+* `worker`: shorthand for the dedicated, shared, and service worker scopes
+
+To check if your test is run from a window or worker you can use the following two methods that will
+be made available by the framework:
+
+    self.GLOBAL.isWindow()
+    self.GLOBAL.isWorker()
+
+Although [the global `done` function must be explicitly invoked for most
+dedicated worker tests and shared worker
+tests](testharness-api.html#determining-when-all-tests-are-complete), it is
+automatically invoked for tests defined using the "multi-global" pattern.
+
+### Specifying a test title in auto-generated boilerplate tests
+
+Use `// META: title=This is the title of the test` at the beginning of the resource.
+
+### Including other JavaScript resources in auto-generated boilerplate tests
+
+Use `// META: script=link/to/resource.js` at the beginning of the resource. For example,
+
+```
+// META: script=/common/utils.js
+// META: script=resources/utils.js
+```
+
+can be used to include both the global and a local `utils.js` in a test.
+
+### Specifying a timeout of long in auto-generated boilerplate tests
+
+Use `// META: timeout=long` at the beginning of the resource.
+
+### Specifying test [variants](#variants) in auto-generated boilerplate tests
+
+Use `// META: variant=url-suffix` at the beginning of the resource. For example,
+
+```
+// META: variant=
+// META: variant=?wss
+```
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/tools.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/tools.md
new file mode 100644
index 0000000..0a9a7dc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/tools.md
@@ -0,0 +1,25 @@
+# Command-line utility scripts
+
+Sometimes you may want to add a script to the repository that's meant to be
+used from the command line, not from a browser (e.g., a script for generating
+test files). If you want to ensure (e.g., for security reasons) that such
+scripts won't be handled by the HTTP server, but will instead only be usable
+from the command line, then place them in either:
+
+* the `tools` subdir at the root of the repository, or
+
+* the `tools` subdir at the root of any top-level directory in the repository
+  which contains the tests the script is meant to be used with
+
+Any files in those `tools` directories won't be handled by the HTTP server;
+instead the server will return a 404 if a user navigates to the URL for a file
+within them.
+
+If you want to add a script for use with a particular set of tests but there
+isn't yet any `tools` subdir at the root of a top-level directory in the
+repository containing those tests, you can create a `tools` subdir at the root
+of that top-level directory and place your scripts there.
+
+For example, if you wanted to add a script for use with tests in the
+`notifications` directory, create the `notifications/tools` subdir and put your
+script there.
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/visual.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/visual.md
new file mode 100644
index 0000000..a8ae53d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/visual.md
@@ -0,0 +1,27 @@
+# Visual Tests
+
+Visual tests are typically used when testing rendering of things that
+cannot be tested with [reftests](reftests).
+
+Their main advantage of over manual tests is they can be verified using
+browser-specific and platform-specific screenshots; note, however, that many
+browser vendors treat them identically to manual tests hence they are
+similarly discouraged as they very infrequently, if ever, get run by them.
+
+## Writing a Visual Test
+
+Visuals tests are test files which have `-visual` at the end of their
+filename, before the extension. There is nothing needed in them to
+make them work.
+
+They should follow the [general test guidelines](general-guidelines),
+especially noting the requirement to be self-describing (i.e., they
+must give a clear pass condition in their rendering).
+
+Similarly, they should consider the [rendering test guidelines](rendering),
+especially those about color, to ensure those running the test don't
+incorrectly judge its result.
+
+The screenshot for comparison is taken at the same point as when screenshots
+for [reftest comparisons](reftests) are taken, including potentially waiting
+for any `class="reftest-wait"` to be removed from the root element.
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/wdspec.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/wdspec.md
new file mode 100644
index 0000000..16bdb93
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/wdspec.md
@@ -0,0 +1,69 @@
+# wdspec tests
+
+The term "wdspec" describes a type of test in WPT which verifies some aspect of
+[the WebDriver protocol](https://w3c.github.io/webdriver/). These tests are
+written in [the Python programming language](https://www.python.org/) and
+structured with [the pytest testing
+framework](https://docs.pytest.org/en/latest/).
+
+The test files are organized into subdirectories based on the WebDriver
+command under test. For example, tests for [the Close Window
+command](https://w3c.github.io/webdriver/#close-window) are located in then
+`close_window` directory.
+
+Similar to [testharness.js](testharness) tests, wdspec tests contain within
+them any number of "sub-tests." Sub-tests are defined as Python functions whose
+name begins with `test_`, e.g. `test_stale_element`.
+
+## The `webdriver` client library
+
+web-platform-tests maintains a WebDriver client library called `webdriver`
+located in the `tools/webdriver/` directory. Like other client libraries, it
+makes it easier to write code which interfaces with a browser using the
+protocol.
+
+Many tests require some "set up" code--logic intended to bring the browser to a
+known state from which the expected behavior can be verified. The convenience
+methods in the `webdriver` library **should** be used to perform this task
+because they reduce duplication.
+
+However, the same methods **should not** be used to issue the command under
+test. Instead, the HTTP request describing the command should be sent directly.
+This practice promotes the descriptive quality of the tests and limits
+indirection that tends to obfuscate test failures.
+
+Here is an example of a test for [the Element Click
+command](https://w3c.github.io/webdriver/#element-click):
+
+```python
+from tests.support.asserts import assert_success
+from tests.support.inline import inline
+
+def test_null_response_value(session):
+    # The high-level API is used to set up a document and locate a click target
+    session.url = inline("<p>foo")
+    element = session.find.css("p", all=False)
+
+    # An HTTP request is explicitly constructed for the "click" command itself
+    response = session.transport.send(
+        "POST", "session/{session_id}/element/{element_id}/click".format(
+            session_id=session.session_id,
+            element_id=element.id))
+
+    assert_success(response)
+```
+
+## Utility functions
+
+The `wedbdriver` library is minimal by design. It mimics the structure of the
+WebDriver specification. Many conformance tests perform similar operations
+(e.g. calculating the center point of an element or creating a document), but
+the library does not expose methods to facilitate them. Instead, wdspec tests
+define shared functionality in the form of "support" files.
+
+Many of these functions are intended to be used directly from the tests using
+Python's built-in `import` keyword. Others (particularly those that operate on
+a WebDriver session) are defined in terms of Pytest "fixtures" and must be
+loaded accordingly. For more detail on how to define and use test fixtures,
+please refer to [the pytest project's documentation on the
+topic](https://docs.pytest.org/en/latest/fixture.html).
diff --git a/third_party/blink/web_tests/external/wpt/document-policy/font-display/override-to-optional.tentative-ref.html b/third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-01.tentative-ref.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/document-policy/font-display/override-to-optional.tentative-ref.html
rename to third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-01.tentative-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/document-policy/font-display/override-to-optional.tentative.html b/third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-01.tentative.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/document-policy/font-display/override-to-optional.tentative.html
rename to third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-01.tentative.html
index 26927bb..cad4c18 100644
--- a/third_party/blink/web_tests/external/wpt/document-policy/font-display/override-to-optional.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-01.tentative.html
@@ -2,7 +2,7 @@
 <html class="reftest-wait">
 <title>Test for no-font-display-late-swap document policy behavior</title>
 <link rel="help" href="https://github.com/w3c/webappsec-feature-policy/blob/master/policies/font-display-late-swap.md">
-<link rel="match" href="override-to-optional.tentative-ref.html">
+<link rel="match" href="font-display-document-policy-01.tentative-ref.html">
 <style>
 </style>
 <p>Tests if font-display is set to optional for each option except for when it is set to fallback</p>
diff --git a/third_party/blink/web_tests/external/wpt/document-policy/font-display/override-to-optional.tentative.html.headers b/third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-01.tentative.html.headers
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/document-policy/font-display/override-to-optional.tentative.html.headers
rename to third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-01.tentative.html.headers
diff --git a/third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-report-only.tentative.html b/third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-report-only.tentative.html
new file mode 100644
index 0000000..03fa5b68
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-report-only.tentative.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Test for font-display-late-swap feature policy set to report-only</title>
+    <link rel="help" href="https://github.com/w3c/webappsec-feature-policy/blob/master/policies/font-display-late-swap.md">
+    <script src='/resources/testharness.js'></script>
+    <script src='/resources/testharnessreport.js'></script>
+    <style>
+    </style>
+  </head>
+  <body>
+    <p>
+      Tests if the correct number of violation reports are generated and each report corresponds to this feature.
+      4 reports should be created out of the 6 options below (reports for all except for 'fallback' and 'optional').
+    </p>
+    <table id="container">
+     <tr>
+      <th>not-set</th>
+      <th>auto</th>
+      <th>block</th>
+      <th>swap</th>
+      <th>fallback</th>
+      <th>optional</th>
+     </tr>
+    </table>
+    <script>
+const fontDisplayValues = ['', 'auto', 'block', 'swap', 'fallback', 'optional'];
+const table = document.getElementById('container');
+
+function makeFontFaceDeclaration(family, display) {
+    url = '/fonts/Ahem.ttf?pipe=trickle(d1)'; // Before the swap period is over
+    return '@font-face { font-family: ' + family + '; src: url("' + url + '"); font-display: ' + display + '; }';
+}
+
+window.onload = () => {
+    let tr = document.createElement('tr');
+    for (let display of fontDisplayValues) {
+        const family = display + '-face';
+        const rule = makeFontFaceDeclaration(family, display);
+        document.styleSheets[0].insertRule(rule, 0);
+        let td = document.createElement('td');
+        td.textContent = 'a';
+        td.style.fontFamily = family + ', Arial';
+        tr.appendChild(td);
+    }
+    table.appendChild(tr);
+}
+
+let reportCounter = 4;
+let t = async_test('font-display-late-swap Report Format');
+
+let check_report_format = (reports, observer) => {
+  reportCounter -= reports.length;
+  for (let report of reports) {
+    assert_equals(report.type, 'document-policy-violation');
+    assert_equals(report.url, document.location.href, 'Report URL');
+    assert_equals(report.body.featureId, 'font-display-late-swap');
+    assert_equals(report.body.disposition, 'report');
+    assert_true('sourceFile' in report.body);
+    assert_true('lineNumber' in report.body);
+    assert_true('columnNumber' in report.body);
+  }
+  // Test is done when we have exactly 4 reports for the following
+  // font-display values: not set, 'auto', 'block', 'swap'
+  if (reportCounter == 0) t.done();
+};
+
+new ReportingObserver(t.step_func(check_report_format),
+                      {types: ['document-policy-violation'], buffered: true}).observe();
+    </script>
+  </body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/document-policy/font-display/resources/report-only-iframe.html.headers b/third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-report-only.tentative.html.headers
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/document-policy/font-display/resources/report-only-iframe.html.headers
rename to third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-report-only.tentative.html.headers
diff --git a/third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-reporting.tentative.html b/third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-reporting.tentative.html
new file mode 100644
index 0000000..db871d1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-reporting.tentative.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Test for font-display-late-swap feature policy set to reporting</title>
+    <link rel="help" href="https://github.com/w3c/webappsec-feature-policy/blob/master/policies/font-display-late-swap.md">
+    <script src='/resources/testharness.js'></script>
+    <script src='/resources/testharnessreport.js'></script>
+    <style>
+    </style>
+  </head>
+  <body>
+    <p>
+      Tests if the correct number of violation reports are generated and each report corresponds to this feature.
+      4 reports should be created out of the 6 options below (reports for all except for 'fallback' and 'optional').
+    </p>
+    <table id="container">
+     <tr>
+      <th>not-set</th>
+      <th>auto</th>
+      <th>block</th>
+      <th>swap</th>
+      <th>fallback</th>
+      <th>optional</th>
+     </tr>
+    </table>
+    <script>
+const fontDisplayValues = ['', 'auto', 'block', 'swap', 'fallback', 'optional'];
+const table = document.getElementById('container');
+
+function makeFontFaceDeclaration(family, display) {
+    url = '/fonts/Ahem.ttf?pipe=trickle(d1)'; // Before the swap period is over
+    return '@font-face { font-family: ' + family + '; src: url("' + url + '"); font-display: ' + display + '; }';
+}
+
+window.onload = () => {
+    let tr = document.createElement('tr');
+    for (let display of fontDisplayValues) {
+        const family = display + '-face';
+        const rule = makeFontFaceDeclaration(family, display);
+        document.styleSheets[0].insertRule(rule, 0);
+        let td = document.createElement('td');
+        td.textContent = 'a';
+        td.style.fontFamily = family + ', Arial';
+        tr.appendChild(td);
+    }
+    table.appendChild(tr);
+}
+
+let reportCounter = 4;
+let t = async_test('font-display-late-swap Report Format');
+
+let check_report_format = (reports, observer) => {
+  reportCounter -= reports.length;
+  for (let report of reports) {
+    assert_equals(report.type, 'document-policy-violation');
+    assert_equals(report.url, document.location.href, 'Report URL');
+    assert_equals(report.body.featureId, 'font-display-late-swap');
+    assert_equals(report.body.disposition, 'enforce');
+    assert_true('sourceFile' in report.body);
+    assert_true('lineNumber' in report.body);
+    assert_true('columnNumber' in report.body);
+  }
+  // Test is done when we have exactly 4 reports for the following
+  // font-display values: not set, 'auto', 'block', 'swap'
+  if (reportCounter == 0) t.done();
+};
+
+new ReportingObserver(t.step_func(check_report_format),
+                      {types: ['document-policy-violation'], buffered: true}).observe();
+    </script>
+  </body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/document-policy/font-display/resources/reporting-iframe.html.headers b/third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-reporting.tentative.html.headers
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/document-policy/font-display/resources/reporting-iframe.html.headers
rename to third_party/blink/web_tests/external/wpt/document-policy/font-display/font-display-document-policy-reporting.tentative.html.headers
diff --git a/third_party/blink/web_tests/external/wpt/document-policy/font-display/report-only.tentative.html b/third_party/blink/web_tests/external/wpt/document-policy/font-display/report-only.tentative.html
deleted file mode 100644
index d528e09..0000000
--- a/third_party/blink/web_tests/external/wpt/document-policy/font-display/report-only.tentative.html
+++ /dev/null
@@ -1,83 +0,0 @@
-<!DOCTYPE html>
-<title>Test for font-display-late-swap feature policy set to report-only</title>
-<link rel="help" href="https://github.com/w3c/webappsec-feature-policy/blob/master/policies/font-display-late-swap.md">
-<script src='/resources/testharness.js'></script>
-<script src='/resources/testharnessreport.js'></script>
-<style></style>
-<p>
-  Tests if the correct number of violation reports are generated and each report corresponds to this feature.
-  4 reports should be created out of the 6 options below (reports for all except for 'fallback' and 'optional').
-</p>
-<table id="container">
-  <tr>
-    <th>not-set</th>
-    <th>auto</th>
-    <th>block</th>
-    <th>swap</th>
-    <th>fallback</th>
-    <th>optional</th>
-  </tr>
-</table>
-<script>
-  const fontDisplayValues = ['', 'auto', 'block', 'swap', 'fallback', 'optional'];
-  const table = document.getElementById('container');
-  const t = async_test('font-display-late-swap Report Format');
-
-  function makeFontFaceDeclaration(family, display) {
-    url = '/fonts/Ahem.ttf?pipe=trickle(d1)'; // Before the swap period is over
-    return `@font-face { font-family: ${family}; src: url("${url}"); font-display: ${display}; }`;
-  }
-
-  window.onload = () => {
-    let tr = document.createElement('tr');
-    for (let display of fontDisplayValues) {
-      const family = display + '-face';
-      const rule = makeFontFaceDeclaration(family, display);
-
-      // Create a separate iframe for testing purpose.
-      // For same document, violation reports with same content might be deduped.
-      let iframe = document.createElement('iframe');
-      iframe.src = 'resources/report-only-iframe.html';
-      iframe.onload = t.step_func(() => {
-        iframe.contentWindow.postMessage({
-          display,
-          family,
-          rule
-        }, '*');
-      });
-
-      let td = document.createElement('td');
-      td.appendChild(iframe);
-      tr.appendChild(td);
-    }
-    table.appendChild(tr);
-  }
-
-  function check_report_format(report) {
-    assert_equals(report.type, 'document-policy-violation');
-    assert_equals(report.url, document.getElementsByTagName('iframe')[0].contentWindow.location.href);
-    assert_equals(report.body.featureId, 'font-display-late-swap');
-    assert_equals(report.body.disposition, 'report');
-    assert_true('sourceFile' in report.body);
-    assert_true('lineNumber' in report.body);
-    assert_true('columnNumber' in report.body);
-  };
-
-  const expectedFontDisplayValues = ['', 'auto', 'block', 'swap']
-  expectedFontDisplayValues.sort();
-  const fontDisplayValuesReceived = [];
-  window.onmessage = t.step_func((e) => {
-    const reports = JSON.parse(e.data.reports);
-    assert_equals(reports.length, 1);
-    check_report_format(reports[0]);
-    fontDisplayValuesReceived.push(e.data.fontDisplayValue);
-
-    // Test is done when we have exactly 4 reports for the following
-    // font-display values: not set, 'auto', 'block', 'swap'
-    if (fontDisplayValuesReceived.length == 4) {
-      fontDisplayValuesReceived.sort();
-      assert_array_equals(fontDisplayValuesReceived, expectedFontDisplayValues);
-      t.done();
-    }
-  });
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/document-policy/font-display/reporting.tentative.html b/third_party/blink/web_tests/external/wpt/document-policy/font-display/reporting.tentative.html
deleted file mode 100644
index 91927f4..0000000
--- a/third_party/blink/web_tests/external/wpt/document-policy/font-display/reporting.tentative.html
+++ /dev/null
@@ -1,83 +0,0 @@
-<!DOCTYPE html>
-<title>Test for font-display-late-swap feature policy</title>
-<link rel="help" href="https://github.com/w3c/webappsec-feature-policy/blob/master/policies/font-display-late-swap.md">
-<script src='/resources/testharness.js'></script>
-<script src='/resources/testharnessreport.js'></script>
-<style></style>
-<p>
-  Tests if the correct number of violation reports are generated and each report corresponds to this feature.
-  4 reports should be created out of the 6 options below (reports for all except for 'fallback' and 'optional').
-</p>
-<table id="container">
-  <tr>
-    <th>not-set</th>
-    <th>auto</th>
-    <th>block</th>
-    <th>swap</th>
-    <th>fallback</th>
-    <th>optional</th>
-  </tr>
-</table>
-<script>
-  const fontDisplayValues = ['', 'auto', 'block', 'swap', 'fallback', 'optional'];
-  const table = document.getElementById('container');
-  const t = async_test('font-display-late-swap Report Format');
-
-  function makeFontFaceDeclaration(family, display) {
-    url = '/fonts/Ahem.ttf?pipe=trickle(d1)'; // Before the swap period is over
-    return `@font-face { font-family: ${family}; src: url("${url}"); font-display: ${display}; }`;
-  }
-
-  window.onload = () => {
-    let tr = document.createElement('tr');
-    for (let display of fontDisplayValues) {
-      const family = display + '-face';
-      const rule = makeFontFaceDeclaration(family, display);
-
-      // Create a separate iframe for testing purpose.
-      // For same document, violation reports with same content might be deduped.
-      let iframe = document.createElement('iframe');
-      iframe.src = 'resources/reporting-iframe.html';
-      iframe.onload = t.step_func(() => {
-        iframe.contentWindow.postMessage({
-          display,
-          family,
-          rule
-        }, '*');
-      });
-
-      let td = document.createElement('td');
-      td.appendChild(iframe);
-      tr.appendChild(td);
-    }
-    table.appendChild(tr);
-  }
-
-  function check_report_format(report) {
-    assert_equals(report.type, 'document-policy-violation');
-    assert_equals(report.url, document.getElementsByTagName('iframe')[0].contentWindow.location.href);
-    assert_equals(report.body.featureId, 'font-display-late-swap');
-    assert_equals(report.body.disposition, 'enforce');
-    assert_true('sourceFile' in report.body);
-    assert_true('lineNumber' in report.body);
-    assert_true('columnNumber' in report.body);
-  };
-
-  const expectedFontDisplayValues = ['', 'auto', 'block', 'swap']
-  expectedFontDisplayValues.sort();
-  const fontDisplayValuesReceived = [];
-  window.onmessage = t.step_func((e) => {
-    const reports = JSON.parse(e.data.reports);
-    assert_equals(reports.length, 1);
-    check_report_format(reports[0]);
-    fontDisplayValuesReceived.push(e.data.fontDisplayValue);
-
-    // Test is done when we have exactly 4 reports for the following
-    // font-display values: not set, 'auto', 'block', 'swap'
-    if (fontDisplayValuesReceived.length == 4) {
-      fontDisplayValuesReceived.sort();
-      assert_array_equals(fontDisplayValuesReceived, expectedFontDisplayValues);
-      t.done();
-    }
-  });
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/document-policy/font-display/resources/report-only-iframe.html b/third_party/blink/web_tests/external/wpt/document-policy/font-display/resources/report-only-iframe.html
deleted file mode 100644
index 703739a..0000000
--- a/third_party/blink/web_tests/external/wpt/document-policy/font-display/resources/report-only-iframe.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<style></style>
-<p>This is a subframe with 'no-font-display-late-swap'</p>
-<p id="text"></p>
-<script>
-  window.onmessage = (e) => {
-    const rule = e.data.rule;
-    const family = e.data.family;
-    // Id used to distinguish response source in main frame.
-    const display = e.data.display;
-
-    function send_report(reports) {
-      // stringify reports because report is not clonable.
-      e.source.postMessage({
-        fontDisplayValue: display,
-        reports: JSON.stringify(reports)
-      }, '*');
-    }
-
-    new ReportingObserver(send_report, {
-        types: ['document-policy-violation'],
-        buffered: true
-      })
-      .observe();
-
-    document.styleSheets[0].insertRule(rule, 0);
-    // Trigger font display violation.
-    const p = document.getElementById('text');
-    p.textContent = 'a';
-    p.style.fontFamily = `${family}, Arial`;
-  };
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/document-policy/font-display/resources/reporting-iframe.html b/third_party/blink/web_tests/external/wpt/document-policy/font-display/resources/reporting-iframe.html
deleted file mode 100644
index 703739a..0000000
--- a/third_party/blink/web_tests/external/wpt/document-policy/font-display/resources/reporting-iframe.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<style></style>
-<p>This is a subframe with 'no-font-display-late-swap'</p>
-<p id="text"></p>
-<script>
-  window.onmessage = (e) => {
-    const rule = e.data.rule;
-    const family = e.data.family;
-    // Id used to distinguish response source in main frame.
-    const display = e.data.display;
-
-    function send_report(reports) {
-      // stringify reports because report is not clonable.
-      e.source.postMessage({
-        fontDisplayValue: display,
-        reports: JSON.stringify(reports)
-      }, '*');
-    }
-
-    new ReportingObserver(send_report, {
-        types: ['document-policy-violation'],
-        buffered: true
-      })
-      .observe();
-
-    document.styleSheets[0].insertRule(rule, 0);
-    // Trigger font display violation.
-    const p = document.getElementById('text');
-    p.textContent = 'a';
-    p.style.fontFamily = `${family}, Arial`;
-  };
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/Node-cloneNode-on-inactive-document-crash.html b/third_party/blink/web_tests/external/wpt/dom/nodes/Node-cloneNode-on-inactive-document-crash.html
new file mode 100644
index 0000000..cbd7a1e6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/Node-cloneNode-on-inactive-document-crash.html
@@ -0,0 +1,6 @@
+<iframe id="i"></iframe>
+<script>
+var doc = i.contentDocument;
+i.remove();
+doc.cloneNode();
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/mousedown.html b/third_party/blink/web_tests/external/wpt/event-timing/mousedown.html
index e0f14f4c..35a07fa 100644
--- a/third_party/blink/web_tests/external/wpt/event-timing/mousedown.html
+++ b/third_party/blink/web_tests/external/wpt/event-timing/mousedown.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <meta charset=utf-8 />
+<meta name="timeout" content="long">
 <title>Event Timing mousedown.</title>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/pointerdown.html b/third_party/blink/web_tests/external/wpt/event-timing/pointerdown.html
index 3d7dcbe8..2eb6ae89 100644
--- a/third_party/blink/web_tests/external/wpt/event-timing/pointerdown.html
+++ b/third_party/blink/web_tests/external/wpt/event-timing/pointerdown.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <meta charset=utf-8 />
+<meta name="timeout" content="long">
 <title>Event Timing pointerdown.</title>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
diff --git a/third_party/blink/web_tests/external/wpt/eventsource/format-field-id-3.window.js b/third_party/blink/web_tests/external/wpt/eventsource/format-field-id-3.window.js
new file mode 100644
index 0000000..3766fbf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/eventsource/format-field-id-3.window.js
@@ -0,0 +1,56 @@
+const ID_PERSISTS = 1,
+ID_RESETS_1 = 2,
+ID_RESETS_2 = 3;
+
+async_test(testPersist, "EventSource: lastEventId persists");
+async_test(testReset(ID_RESETS_1), "EventSource: lastEventId resets");
+async_test(testReset(ID_RESETS_2), "EventSource: lastEventId resets (id without colon)");
+
+function testPersist(t) {
+    const source = new EventSource("resources/last-event-id2.py?type=" + ID_PERSISTS);
+    let counter = 0;
+    t.add_cleanup(() => source.close());
+    source.onmessage = t.step_func(e => {
+      counter++;
+      if (counter === 1) {
+          assert_equals(e.lastEventId, "1");
+          assert_equals(e.data, "1");
+      } else if (counter === 2) {
+          assert_equals(e.lastEventId, "1");
+          assert_equals(e.data, "2");
+      } else if (counter === 3) {
+          assert_equals(e.lastEventId, "2");
+          assert_equals(e.data, "3");
+      } else if (counter === 4) {
+          assert_equals(e.lastEventId, "2");
+          assert_equals(e.data, "4");
+          t.done();
+      } else {
+          assert_unreached();
+      }
+  });
+}
+
+function testReset(type) {
+  return function (t) {
+    const source = new EventSource("resources/last-event-id2.py?type=" + type);
+    let counter = 0;
+    t.add_cleanup(() => source.close());
+    source.onmessage = t.step_func(e => {
+      counter++;
+      if (counter === 1) {
+        assert_equals(e.lastEventId, "1");
+        assert_equals(e.data, "1");
+      } else if (counter === 2) {
+        assert_equals(e.lastEventId, "");
+        assert_equals(e.data, "2");
+      } else if (counter === 3) {
+        assert_equals(e.lastEventId, "");
+        assert_equals(e.data, "3");
+        t.done();
+      } else {
+          assert_unreached();
+      }
+    });
+  }
+}
diff --git a/third_party/blink/web_tests/external/wpt/eventsource/resources/last-event-id2.py b/third_party/blink/web_tests/external/wpt/eventsource/resources/last-event-id2.py
new file mode 100644
index 0000000..4f133d70
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/eventsource/resources/last-event-id2.py
@@ -0,0 +1,23 @@
+ID_PERSISTS = 1
+ID_RESETS_1 = 2
+ID_RESETS_2 = 3
+
+def main(request, response):
+  response.headers.set(b"Content-Type", b"text/event-stream")
+  try:
+    test_type = int(request.GET.first(b"type", ID_PERSISTS))
+  except:
+    test_type = ID_PERSISTS
+
+  if test_type == ID_PERSISTS:
+    return b"id: 1\ndata: 1\n\ndata: 2\n\nid: 2\ndata:3\n\ndata:4\n\n"
+
+  elif test_type == ID_RESETS_1:
+    return b"id: 1\ndata: 1\n\nid:\ndata:2\n\ndata:3\n\n"
+
+  # empty id field without colon character (:) should also reset
+  elif test_type == ID_RESETS_2:
+    return b"id: 1\ndata: 1\n\nid\ndata:2\n\ndata:3\n\n"
+
+  else:
+    return b"data: invalid_test\n\n"
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/select-size-001.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/select-size-001.html
new file mode 100644
index 0000000..ad40554
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/select-size-001.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<title>select size=1 renders the same as plain select</title>
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1643279">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="match" href="select-size-ref.html">
+<select size="1">
+  <option value ="1">1</option>
+  <option value ="2">2</option>
+  <option value ="3">3</option>
+</select>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/select-size-002.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/select-size-002.html
new file mode 100644
index 0000000..0838e7a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/select-size-002.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<title>select size=0 renders the same as plain select</title>
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1643279">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="match" href="select-size-ref.html">
+<select size="0">
+  <option value ="1">1</option>
+  <option value ="2">2</option>
+  <option value ="3">3</option>
+</select>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/select-size-ref.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/select-size-ref.html
new file mode 100644
index 0000000..fc3b3be6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/select-size-ref.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<title>Test reference.</title>
+<select>
+  <option value ="1">1</option>
+  <option value ="2">2</option>
+  <option value ="3">3</option>
+</select>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-relevant-mutations-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-relevant-mutations-expected.txt
deleted file mode 100644
index e420732..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-relevant-mutations-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-PASS Images are lazyloaded
-FAIL Image referrerPolicy mutation does not cause deferred loading=lazy images to be fetched promise_test: Unhandled rejection with value: object "[object Event]"
-FAIL Image crossOrigin mutation does not cause deferred loading=lazy images to be fetched promise_test: Unhandled rejection with value: object "[object Event]"
-FAIL Image src mutation does not cause deferred loading=lazy images to be fetched promise_test: Unhandled rejection with value: object "[object Event]"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/input-device-capabilities/idlharness.window.js b/third_party/blink/web_tests/external/wpt/input-device-capabilities/idlharness.window.js
index a57ae829..fe4d01f 100644
--- a/third_party/blink/web_tests/external/wpt/input-device-capabilities/idlharness.window.js
+++ b/third_party/blink/web_tests/external/wpt/input-device-capabilities/idlharness.window.js
@@ -1,10 +1,11 @@
 // META: script=/resources/WebIDLParser.js
 // META: script=/resources/idlharness.js
+// META: timeout=long
 
 'use strict';
 
 idl_test(
-  ['InputDeviceCapabilities'],
+  ['input-device-capabilities'],
   ['uievents', 'dom'],
   idl_array => {
     idl_array.add_objects({
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/CSS-Parser-API.idl b/third_party/blink/web_tests/external/wpt/interfaces/css-parser-api.idl
similarity index 97%
rename from third_party/blink/web_tests/external/wpt/interfaces/CSS-Parser-API.idl
rename to third_party/blink/web_tests/external/wpt/interfaces/css-parser-api.idl
index 57ee7b73..f3e5867 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/CSS-Parser-API.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/css-parser-api.idl
@@ -1,7 +1,7 @@
 // GENERATED CONTENT - DO NOT EDIT
 // Content was automatically extracted by Reffy into reffy-reports
 // (https://github.com/tidoust/reffy-reports)
-// Source: CSS Parser API (https://wicg.github.io/CSS-Parser-API/)
+// Source: CSS Parser API (https://wicg.github.io/css-parser-api/)
 
 typedef (DOMString or ReadableStream) CSSStringSource;
 typedef (DOMString or CSSStyleValue or CSSParserValue) CSSToken;
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/InputDeviceCapabilities.idl b/third_party/blink/web_tests/external/wpt/interfaces/input-device-capabilities.idl
similarity index 88%
rename from third_party/blink/web_tests/external/wpt/interfaces/InputDeviceCapabilities.idl
rename to third_party/blink/web_tests/external/wpt/interfaces/input-device-capabilities.idl
index cb5d2827..86015b3 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/InputDeviceCapabilities.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/input-device-capabilities.idl
@@ -1,7 +1,7 @@
 // GENERATED CONTENT - DO NOT EDIT
 // Content was automatically extracted by Reffy into reffy-reports
 // (https://github.com/tidoust/reffy-reports)
-// Source: Input Device Capabilities (https://wicg.github.io/InputDeviceCapabilities/)
+// Source: Input Device Capabilities (https://wicg.github.io/input-device-capabilities/)
 
 [Exposed=Window,
  Constructor(optional InputDeviceCapabilitiesInit deviceInitDict = {})]
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/scroll-animations.idl b/third_party/blink/web_tests/external/wpt/interfaces/scroll-animations.idl
index 00d0bae..33fb59b 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/scroll-animations.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/scroll-animations.idl
@@ -15,8 +15,8 @@
 dictionary ScrollTimelineOptions {
   Element? source = null;
   ScrollDirection orientation = "block";
-  DOMString start = "auto";
-  DOMString end = "auto";
+  (DOMString or ElementBasedOffset) start = "auto";
+  (DOMString or ElementBasedOffset) end = "auto";
   (double or ScrollTimelineAutoKeyword) timeRange = "auto";
 };
 
@@ -29,3 +29,10 @@
   readonly attribute DOMString end;
   readonly attribute (double or ScrollTimelineAutoKeyword) timeRange;
 };
+
+enum Edge { "start", "end" };
+
+dictionary ElementBasedOffset {
+  Element target;
+  Edge edge = "start";
+};
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/webdriver.idl b/third_party/blink/web_tests/external/wpt/interfaces/webdriver.idl
index 00dc148..3ab991b 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/webdriver.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/webdriver.idl
@@ -3,8 +3,7 @@
 // (https://github.com/tidoust/reffy-reports)
 // Source: WebDriver (https://w3c.github.io/webdriver/)
 
-Navigator includes NavigatorAutomationInformation;
-
 interface mixin NavigatorAutomationInformation {
   readonly attribute boolean webdriver;
 };
+Navigator includes NavigatorAutomationInformation;
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/xhr.idl b/third_party/blink/web_tests/external/wpt/interfaces/xhr.idl
index de47873..d3d0e53 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/xhr.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/xhr.idl
@@ -50,7 +50,7 @@
            attribute unsigned long timeout;
            attribute boolean withCredentials;
   [SameObject] readonly attribute XMLHttpRequestUpload upload;
-  void send(optional (Document or BodyInit)? body = null);
+  void send(optional (Document or XMLHttpRequestBodyInit)? body = null);
   void abort();
 
   // response
diff --git a/third_party/blink/web_tests/external/wpt/lint.ignore b/third_party/blink/web_tests/external/wpt/lint.ignore
index dc6a284..9d057e7 100644
--- a/third_party/blink/web_tests/external/wpt/lint.ignore
+++ b/third_party/blink/web_tests/external/wpt/lint.ignore
@@ -295,7 +295,7 @@
 SET TIMEOUT: css/css-fonts/font-display/font-display-feature-policy-01.tentative.html
 SET TIMEOUT: css/css-fonts/font-display/font-display-feature-policy-02.tentative.html
 SET TIMEOUT: css/css-fonts/font-display/font-display-preload.html
-SET TIMEOUT: document-policy/font-display/override-to-optional.tentative.html
+SET TIMEOUT: document-policy/font-display/font-display-document-policy-01.tentative.html
 SET TIMEOUT: feature-policy/experimental-features/resources/focus-without-user-activation-iframe-tentative.html
 SET TIMEOUT: html/browsers/windows/auxiliary-browsing-contexts/resources/close-opener.html
 SET TIMEOUT: html/cross-origin-embedder-policy/resources/navigate-none.sub.html
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid-2-ref.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid-2-ref.html
new file mode 100644
index 0000000..5b1960d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid-2-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mfrac with one child</title>
+</head>
+<body>
+  <p>This test passes if you see a single rectangle.</p>
+  <math>
+    <mrow>
+      <mspace width="200px" height="200px" style="background: green"></mspace>
+    </mrow>
+  </math>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid-2.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid-2.html
new file mode 100644
index 0000000..4bd72c76
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid-2.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mfrac with one child</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#mfrac">
+<meta name="assert" content="An mfrac with one child should render using mrow.">
+<link rel="match" href="frac-invalid-2-ref.html">
+</head>
+<body>
+  <p>This test passes if you see a single rectangle.</p>
+  <math>
+    <mfrac>
+      <mspace width="200px" height="200px" style="background: green"></mspace>
+    </mfrac>
+  </math>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid-3-ref.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid-3-ref.html
new file mode 100644
index 0000000..7cb95aca
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid-3-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mfrac with three children</title>
+</head>
+<body>
+  <p>This test passes if you see a single rectangle.</p>
+  <math>
+    <mrow>
+      <mspace width="50px" height="200px" style="background: green"></mspace>
+      <mspace width="50px" height="200px" style="background: green"></mspace>
+      <mspace width="100px" height="200px" style="background: green"></mspace>
+    </mrow>
+  </math>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid-3.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid-3.html
new file mode 100644
index 0000000..056e9b6b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid-3.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mfrac with three children</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#mfrac">
+<meta name="assert" content="An mfrac with no children should render using an empty mrow.">
+<link rel="match" href="frac-invalid-3-ref.html">
+</head>
+<body>
+  <p>This test passes if you see a single rectangle.</p>
+  <math>
+    <mfrac>
+      <mspace width="50px" height="200px" style="background: green"></mspace>
+      <mspace width="50px" height="200px" style="background: green"></mspace>
+      <mspace width="100px" height="200px" style="background: green"></mspace>
+    </mfrac>
+  </math>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid-ref.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid-ref.html
new file mode 100644
index 0000000..e1c44fe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mfrac with zero children</title>
+</head>
+<body>
+  <p>This test passes if mfrac renders nothing.</p>
+  <math>
+    <mrow>
+    </mrow>
+  </math>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid.html
new file mode 100644
index 0000000..cefae79
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-invalid.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mfrac with zero children</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#mfrac">
+<meta name="assert" content="An mfrac with no children should render using an empty mrow.">
+<link rel="match" href="frac-invalid-ref.html">
+</head>
+<body>
+  <p>This test passes if mfrac renders nothing.</p>
+  <math>
+    <mfrac>
+    </mfrac>
+  </math>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mpadded/mpadded-001-expected.txt b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mpadded/mpadded-001-expected.txt
new file mode 100644
index 0000000..f6520243
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mpadded/mpadded-001-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+PASS mpadded (no attributes)
+FAIL Different widths assert_approx_equals: width 0 expected 25 +/- 1 but got 0
+FAIL Different heights assert_approx_equals: height0 expected 25 +/- 1 but got 0
+FAIL Different depths assert_approx_equals: depth0 expected 25 +/- 1 but got 0
+FAIL Various combinations of height, depth and width. assert_approx_equals: width0 expected 25 +/- 1 but got 0
+PASS Preferred width
+PASS dynamic attributes (remove)
+FAIL dynamic attributes (attach) assert_approx_equals: expected 50 +/- 1 but got 0
+FAIL dynamic attributes (modify) assert_approx_equals: expected 50 +/- 1 but got 0
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mpadded/mpadded-001.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mpadded/mpadded-001.html
new file mode 100644
index 0000000..edb2954
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mpadded/mpadded-001.html
@@ -0,0 +1,147 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mpadded</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#adjust-space-around-content-mpadded">
+<meta name="assert" content="Verify metrics of empty mpadded element for different values of height, depth and width">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+  var epsilon = 1;
+  function getBox(aId) {
+    return document.getElementById(aId).getBoundingClientRect();
+  }
+
+  setup({ explicit_done: true });
+  window.addEventListener("load", runTests);
+
+  function runTests() {
+    test(function() {
+      var none = getBox("none");
+      assert_equals(none.width, 0, "zero width");
+      assert_approx_equals(getBox("baseline").bottom - none.top, 0, epsilon, "zero depth");
+      assert_approx_equals(none.bottom - getBox("baseline").bottom, 0, epsilon, "zero depth");
+    }, "mpadded (no attributes)");
+
+    test(function() {
+      for (var i = 0; i <= 2; i++) {
+        var mpadded = getBox("width" + i);
+        assert_approx_equals(mpadded.width, 25*(i+1), epsilon, "width " + i);
+        assert_approx_equals(getBox("baseline").bottom - mpadded.top, 0, epsilon, "height" + i);
+        assert_approx_equals(mpadded.bottom - getBox("baseline").bottom, 0, epsilon, "depth" + i);
+      }
+    }, "Different widths");
+
+    test(function() {
+      for (var i = 0; i <= 2; i++) {
+        var mpadded = getBox("height" + i);
+        assert_equals(mpadded.width, 0, "width" + i);
+        assert_approx_equals(getBox("baseline").bottom - mpadded.top, 25*(i+1), epsilon, "height" + i);
+        assert_approx_equals(mpadded.bottom - getBox("baseline").bottom, 0, epsilon, "depth" + i);
+      }
+    }, "Different heights");
+
+    test(function() {
+      for (var i = 0; i <= 2; i++) {
+        var mpadded = getBox("depth" + i);
+        assert_equals(mpadded.width, 0, "width" + i);
+        assert_approx_equals(getBox("baseline").bottom - mpadded.top, 0, epsilon, "height" + i);
+        assert_approx_equals(mpadded.bottom - getBox("baseline").bottom, 25*(i+1), epsilon, "depth" + i);
+      }
+    }, "Different depths");
+
+    test(function() {
+      for (var i = 0; i <= 2; i++) {
+        var mpadded = getBox("mpadded" + i);
+        assert_approx_equals(mpadded.width, 25*(1+i%3), epsilon, "width" + i);
+        assert_approx_equals(getBox("baseline").bottom - mpadded.top, 25*(1+(i+1)%3), epsilon, "height" + i);
+        assert_approx_equals(mpadded.bottom - getBox("baseline").bottom, 25*(1+(i+2)%3), epsilon, "depth" + i);
+      }
+    }, "Various combinations of height, depth and width.");
+
+    test(function() {
+      var container = document.getElementById("containerForPreferredWidth");
+      var mpadded = container.getElementsByTagName("mpadded")[0];
+      var containerWidth = container.getBoundingClientRect().width;
+      var mpaddedWidth = mpadded.getBoundingClientRect().width;
+      assert_approx_equals(containerWidth, mpaddedWidth, epsilon);
+    }, "Preferred width");
+
+    // Dynamically set attributes.
+    ["width", "height", "depth"].forEach(function (name, index) {
+        document.getElementById("dynamic-remove").removeAttribute(name);
+        let length = `${50 + index * 10}px`;
+        document.getElementById("dynamic-attach").setAttribute(name, length);
+        document.getElementById("dynamic-modify").setAttribute(name, length);
+    });
+    let baseline = getBox("baseline2").bottom;
+
+    test(function() {
+        let remove = getBox("dynamic-remove");
+        assert_approx_equals(remove.width, 0, epsilon);
+        assert_approx_equals(remove.height, 0, epsilon);
+        assert_approx_equals(remove.top, baseline, epsilon);
+    }, "dynamic attributes (remove)");
+
+    test(function() {
+        let attach = getBox("dynamic-attach");
+        assert_approx_equals(attach.width, 50, epsilon);
+        assert_approx_equals(attach.height, 60 + 70, epsilon);
+        assert_approx_equals(baseline - attach.top, 60, epsilon);
+    }, "dynamic attributes (attach)");
+
+    test(function() {
+        let modify = getBox("dynamic-modify");
+        assert_approx_equals(modify.width, 50, epsilon);
+        assert_approx_equals(modify.height, 60 + 70, epsilon);
+        assert_approx_equals(baseline - modify.top, 60, epsilon);
+    }, "dynamic attributes (modify)");
+
+    done();
+  }
+</script>
+<style>
+div.shrink-wrap {
+  background: yellow;
+  display: inline-block;
+  margin-top: 5px;
+  padding-top: 5px;
+}
+</style>
+</head>
+<body>
+  <div id="log"></div>
+  <p>
+    <span id="baseline" style="display: inline-block; width: 30px; height: 5px; background: blue"></span>
+    <math>
+      <mpadded id="none"/>
+      <mpadded id="width0" width="25px"/>
+      <mpadded id="width1" width="50px"/>
+      <mpadded id="width2" width="75px"/>
+      <mpadded id="height0" height="25px"/>
+      <mpadded id="height1" height="50px"/>
+      <mpadded id="height2" height="75px"/>
+      <mpadded id="depth0" depth="25px"/>
+      <mpadded id="depth1" depth="50px"/>
+      <mpadded id="depth2" depth="75px"/>
+      <mpadded id="mpadded0" width="25px" height="50px" depth="75px" style="background: green"/>
+      <mpadded id="mpadded1" width="50px" height="75px" depth="25px" style="background: blue"/>
+      <mpadded id="mpadded2" width="75px" height="25px" depth="50px" style="background: green"/>
+    </math>
+  </p>
+  <div>
+    <div id="containerForPreferredWidth" class="shrink-wrap">
+      <math><mpadded width="75px" height="25px" depth="50px" style="background: green"/></math>
+    </div>
+  </div>
+  <p>
+    <span id="baseline2" style="display: inline-block; width: 30px; height: 5px; background: blue"></span>
+    <math>
+      <mpadded id="dynamic-attach" style="background: lightgreen"/>
+      <mpadded id="dynamic-remove" width="10px" height="20px" depth="30px" style="background: lightyellow"/>
+      <mpadded id="dynamic-modify" width="100px" height="200px" depth="300px" style="background: pink"/>
+    </math>
+  </p>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mpadded/mpadded-002.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mpadded/mpadded-002.html
new file mode 100644
index 0000000..c3cbf7c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mpadded/mpadded-002.html
@@ -0,0 +1,151 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mpadded</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#adjust-space-around-content-mpadded">
+<meta name="assert" content="Verify metrics of nonempty mpadded element for different values of height, depth and width">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+  var epsilon = 1;
+  function getBox(aId) {
+    return document.getElementById(aId).getBoundingClientRect();
+  }
+
+  setup({ explicit_done: true });
+  window.addEventListener("load", runTests);
+
+  function runTests() {
+      const contentWidth = 100;
+      const contentDepth = 125;
+      const contentHeight = 150;
+
+      test(function() {
+      var none = getBox("none");
+      assert_equals(none.width, contentWidth, "content width");
+      assert_approx_equals(getBox("baseline").bottom - none.top, contentHeight, epsilon, "content height");
+      assert_approx_equals(none.bottom - getBox("baseline").bottom, contentDepth, epsilon, "content height");
+    }, "mpadded with no attributes");
+
+    test(function() {
+      for (var i = 0; i <= 2; i++) {
+        var mpadded = getBox("width" + i);
+        assert_approx_equals(mpadded.width, 25*(i+1), epsilon, "width " + i);
+        assert_approx_equals(getBox("baseline").bottom - mpadded.top, contentHeight, epsilon, "height" + i);
+        assert_approx_equals(mpadded.bottom - getBox("baseline").bottom, contentDepth, epsilon, "depth" + i);
+      }
+    }, "Different widths");
+
+    test(function() {
+      for (var i = 0; i <= 2; i++) {
+        var mpadded = getBox("height" + i);
+        assert_equals(mpadded.width, contentWidth, "width" + i);
+        assert_approx_equals(getBox("baseline").bottom - mpadded.top, 25*(i+1), epsilon, "height" + i);
+        assert_approx_equals(mpadded.bottom - getBox("baseline").bottom, contentDepth, epsilon, "depth" + i);
+      }
+    }, "Different heights");
+
+    test(function() {
+      for (var i = 0; i <= 2; i++) {
+        var mpadded = getBox("depth" + i);
+        assert_equals(mpadded.width, contentWidth, "width" + i);
+        assert_approx_equals(getBox("baseline").bottom - mpadded.top, contentHeight, epsilon, "height" + i);
+        assert_approx_equals(mpadded.bottom - getBox("baseline").bottom, 25*(i+1), epsilon, "depth" + i);
+      }
+    }, "Different depths");
+
+    test(function() {
+      for (var i = 0; i <= 2; i++) {
+        var mpadded = getBox("mpadded" + i);
+        assert_approx_equals(mpadded.width, 25*(1+i%3), epsilon, "width" + i);
+        assert_approx_equals(getBox("baseline").bottom - mpadded.top, 25*(1+(i+1)%3), epsilon, "height" + i);
+        assert_approx_equals(mpadded.bottom - getBox("baseline").bottom, 25*(1+(i+2)%3), epsilon, "depth" + i);
+      }
+    }, "Various combinations of height, depth and width.");
+
+    test(function() {
+      var container = document.getElementById("containerForPreferredWidth");
+      var mpadded = container.getElementsByTagName("mpadded")[0];
+      var containerWidth = container.getBoundingClientRect().width;
+      var mpaddedWidth = mpadded.getBoundingClientRect().width;
+      assert_approx_equals(containerWidth, mpaddedWidth, epsilon);
+    }, "Preferred width");
+
+    // Dynamically set attributes.
+    ["width", "height", "depth"].forEach(function (name, index) {
+        document.getElementById("dynamic-remove").removeAttribute(name);
+        let length = `${50 + index * 10}px`;
+        document.getElementById("dynamic-attach").setAttribute(name, length);
+        document.getElementById("dynamic-modify").setAttribute(name, length);
+    });
+    let baseline = getBox("baseline2").bottom;
+
+    test(function() {
+        let remove = getBox("dynamic-remove");
+        assert_approx_equals(remove.width, contentWidth, epsilon);
+        assert_approx_equals(remove.height, contentHeight + contentDepth, epsilon);
+        assert_approx_equals(baseline - remove.top, contentHeight, epsilon);
+    }, "dynamic attributes (remove)");
+
+    test(function() {
+        let attach = getBox("dynamic-attach");
+        assert_approx_equals(attach.width, 50, epsilon);
+        assert_approx_equals(attach.height, 60 + 70, epsilon);
+        assert_approx_equals(baseline - attach.top, 60, epsilon);
+    }, "dynamic attributes (attach)");
+
+    test(function() {
+        let modify = getBox("dynamic-modify");
+        assert_approx_equals(modify.width, 50, epsilon);
+        assert_approx_equals(modify.height, 60 + 70, epsilon);
+        assert_approx_equals(baseline - modify.top, 60, epsilon);
+    }, "dynamic attributes (modify)");
+
+    done();
+  }
+</script>
+<style>
+div.shrink-wrap {
+  background: yellow;
+  display: inline-block;
+  margin-top: 5px;
+  padding-top: 5px;
+}
+</style>
+</head>
+<body>
+  <div id="log"></div>
+  <p>
+    <span id="baseline" style="display: inline-block; width: 30px; height: 5px; background: blue"></span>
+    <math>
+      <mpadded id="none"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+      <mpadded id="width0" width="25px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+      <mpadded id="width1" width="50px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+      <mpadded id="width2" width="75px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+      <mpadded id="height0" height="25px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+      <mpadded id="height1" height="50px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+      <mpadded id="height2" height="75px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+      <mpadded id="depth0" depth="25px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+      <mpadded id="depth1" depth="50px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+      <mpadded id="depth2" depth="75px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+      <mpadded id="mpadded0" width="25px" height="50px" depth="75px" style="background: green"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+      <mpadded id="mpadded1" width="50px" height="75px" depth="25px" style="background: blue"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+      <mpadded id="mpadded2" width="75px" height="25px" depth="50px" style="background: green"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+    </math>
+  </p>
+  <div>
+    <div id="containerForPreferredWidth" class="shrink-wrap">
+      <math><mpadded width="75px" height="25px" depth="50px" style="background: green"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded></math>
+    </div>
+  </div>
+  <p>
+    <span id="baseline2" style="display: inline-block; width: 30px; height: 5px; background: blue"></span>
+    <math>
+      <mpadded id="dynamic-attach" style="background: lightgreen"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+      <mpadded id="dynamic-remove" width="10px" height="20px" depth="30px" style="background: lightyellow"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+      <mpadded id="dynamic-modify" width="100px" height="200px" depth="300px" style="background: pink"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+    </math>
+  </p>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mpadded/mpadded-003-expected.txt b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mpadded/mpadded-003-expected.txt
new file mode 100644
index 0000000..2b658e23
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mpadded/mpadded-003-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+PASS lspace/voffset shifts don't affect mpadded preferred width
+PASS lspace/voffset shifts don't affect mpadded size
+FAIL content is shifted by the specified lspace/voffset assert_approx_equals: positive lspace expected 5 +/- 1 but got 0
+FAIL content is shifted by the specified lspace/voffset (RTL) assert_approx_equals: positive lspace expected -5 +/- 1 but got 0
+FAIL dynamic changes of lspace/voffset assert_approx_equals: attach lspace expected 5 +/- 1 but got 0
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mpadded/mpadded-003.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mpadded/mpadded-003.html
new file mode 100644
index 0000000..4df55b9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mpadded/mpadded-003.html
@@ -0,0 +1,210 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mpadded</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#adjust-space-around-content-mpadded">
+<meta name="assert" content="Verify metrics of mpadded element with voffset and lspace">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+  setup({ explicit_done: true });
+  window.addEventListener("load", runTests);
+
+  function runTests() {
+      const contentWidth = 10;
+      const contentDepth = 15;
+      const contentHeight = 20;
+      const epsilon = 1;
+
+      test(function() {
+          Array.from(document.getElementsByClassName("shrink-wrap")).forEach(container => {
+              assert_approx_equals(container.getBoundingClientRect().width, contentWidth, epsilon);
+          });
+      }, "lspace/voffset shifts don't affect mpadded preferred width");
+
+      function GetShifts(mpadded) {
+          let mpadded_box = mpadded.getBoundingClientRect();
+          let mspace_box = mpadded.firstElementChild.getBoundingClientRect();
+          return { lspace: mspace_box.left - mpadded_box.left,
+                   voffset: mpadded_box.top - mspace_box.top };
+      }
+
+      let mpaddeds = document.getElementById("static_tests").getElementsByTagName("mpadded");
+      test(function() {
+          let baseline = document.getElementById("baseline").getBoundingClientRect().bottom;
+          Array.from(mpaddeds).forEach(e => {
+              let mpadded = e.getBoundingClientRect();
+              assert_approx_equals(mpadded.width, contentWidth, epsilon);
+              assert_approx_equals(baseline - mpadded.top, contentHeight, epsilon);
+              assert_approx_equals(mpadded.bottom - baseline, contentDepth, epsilon);
+
+          });
+      }, "lspace/voffset shifts don't affect mpadded size");
+
+
+      test(function() {
+          let shifts = GetShifts(mpaddeds[0]);
+          assert_approx_equals(shifts.lspace, 5, epsilon, "positive lspace");
+          assert_approx_equals(shifts.voffset, 0, epsilon);
+
+          shifts = GetShifts(mpaddeds[1]);
+          assert_approx_equals(shifts.lspace, 0, epsilon, "negative lspace is clmaped to zero");
+          assert_approx_equals(shifts.voffset, 0, epsilon);
+
+          shifts = GetShifts(mpaddeds[2]);
+          assert_approx_equals(shifts.lspace, 0, epsilon);
+          assert_approx_equals(shifts.voffset, 10, epsilon, "positive voffset");
+
+          shifts = GetShifts(mpaddeds[3]);
+          assert_approx_equals(shifts.lspace, 0, epsilon);
+          assert_approx_equals(shifts.voffset, -10, epsilon, "negative voffset");
+
+          shifts = GetShifts(mpaddeds[4]);
+          assert_approx_equals(shifts.lspace, 5, epsilon);
+          assert_approx_equals(shifts.voffset, 10, epsilon);
+
+          shifts = GetShifts(mpaddeds[5]);
+          assert_approx_equals(shifts.lspace, 5, epsilon);
+          assert_approx_equals(shifts.voffset, -10, epsilon);
+      }, "content is shifted by the specified lspace/voffset");
+
+      mpaddeds = document.getElementById("static_tests_rtl").getElementsByTagName("mpadded");
+      test(function() {
+          let shifts = GetShifts(mpaddeds[0]);
+          assert_approx_equals(shifts.lspace, -5, epsilon, "positive lspace");
+          assert_approx_equals(shifts.voffset, 0, epsilon);
+
+          shifts = GetShifts(mpaddeds[1]);
+          assert_approx_equals(shifts.lspace, 0, epsilon, "negative lspace is clmaped to zero");
+          assert_approx_equals(shifts.voffset, 0, epsilon);
+
+          shifts = GetShifts(mpaddeds[2]);
+          assert_approx_equals(shifts.lspace, 0, epsilon);
+          assert_approx_equals(shifts.voffset, 10, epsilon, "positive voffset");
+
+          shifts = GetShifts(mpaddeds[3]);
+          assert_approx_equals(shifts.lspace, 0, epsilon);
+          assert_approx_equals(shifts.voffset, -10, epsilon, "negative voffset");
+
+          shifts = GetShifts(mpaddeds[4]);
+          assert_approx_equals(shifts.lspace, -5, epsilon);
+          assert_approx_equals(shifts.voffset, 10, epsilon);
+
+          shifts = GetShifts(mpaddeds[5]);
+          assert_approx_equals(shifts.lspace, -5, epsilon);
+          assert_approx_equals(shifts.voffset, -10, epsilon);
+      }, "content is shifted by the specified lspace/voffset (RTL)");
+
+      mpaddeds = document.getElementById("dynamic_tests").getElementsByTagName("mpadded");
+      test(function() {
+          mpaddeds[0].setAttribute("lspace", "5px")
+          let shifts = GetShifts(mpaddeds[0]);
+          assert_approx_equals(shifts.lspace, 5, epsilon, "attach lspace");
+          assert_approx_equals(shifts.voffset, 0, epsilon);
+
+          mpaddeds[1].setAttribute("voffset", "10px")
+          shifts = GetShifts(mpaddeds[1]);
+          assert_approx_equals(shifts.lspace, 0, epsilon);
+          assert_approx_equals(shifts.voffset, 10, epsilon, "attach voffset");
+
+          mpaddeds[2].removeAttribute("lspace")
+          shifts = GetShifts(mpaddeds[2]);
+          assert_approx_equals(shifts.lspace, 0, epsilon, "remove lspace");
+          assert_approx_equals(shifts.voffset, 10, epsilon);
+
+          mpaddeds[3].removeAttribute("voffset")
+          shifts = GetShifts(mpaddeds[3]);
+          assert_approx_equals(shifts.lspace, 5, epsilon);
+          assert_approx_equals(shifts.voffset, 0, epsilon, "remove voffset");
+
+          mpaddeds[4].setAttribute("lspace", "15px")
+          shifts = GetShifts(mpaddeds[4]);
+          assert_approx_equals(shifts.lspace, 15, epsilon, "modify lspace");
+          assert_approx_equals(shifts.voffset, 10, epsilon);
+
+          mpaddeds[5].setAttribute("voffset", "-10px")
+          shifts = GetShifts(mpaddeds[5]);
+          assert_approx_equals(shifts.lspace, 5, epsilon);
+          assert_approx_equals(shifts.voffset, -10, epsilon, "modify voffset");
+      }, "dynamic changes of lspace/voffset");
+
+    done();
+  }
+</script>
+<style>
+div.shrink-wrap {
+  background: yellow;
+  display: inline-block;
+  margin-top: 5px;
+  padding-top: 5px;
+}
+</style>
+</head>
+<body>
+  <div id="log"></div>
+  <div id="static_tests">
+    <span id="baseline" style="display: inline-block; width: 30px; height: 5px; background: blue"></span>
+    <math>
+      <mpadded lspace="5px"  style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      <mpadded lspace="-5px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      <mpadded voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      <mpadded voffset="-10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      <mpadded lspace="5px" voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      <mpadded lspace="5px" voffset="-10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+    </math>
+  </div>
+  <div id="static_tests_rtl">
+    <math dir="rtl">
+      <mpadded lspace="5px"  style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      <mpadded lspace="-5px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      <mpadded voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      <mpadded voffset="-10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      <mpadded lspace="5px" voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      <mpadded lspace="5px" voffset="-10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+    </math>
+  </div>
+  <div id="dynamic_tests">
+    <math>
+      <mpadded style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      <mpadded style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      <mpadded lspace="5px" voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      <mpadded lspace="5px" voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      <mpadded lspace="5px" voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      <mpadded lspace="5px" voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+    </math>
+  </div>
+  <div>
+    <div class="shrink-wrap">
+      <math>
+        <mpadded lspace="5px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      </math>
+    </div>
+    <div class="shrink-wrap">
+      <math>
+        <mpadded lspace="-5px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      </math>
+    </div>
+    <div class="shrink-wrap">
+      <math>
+        <mpadded voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      </math>
+    </div>
+    <div class="shrink-wrap">
+      <math>
+        <mpadded voffset="-10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      </math>
+    </div>
+    <div class="shrink-wrap">
+      <math>
+        <mpadded lspace="5px" voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      </math>
+    </div>
+    <div class="shrink-wrap">
+      <math>
+        <mpadded lspace="5px" voffset="-10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+      </math>
+    </div>
+  </div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/dynamic-childlist-001-expected.txt b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/dynamic-childlist-001-expected.txt
new file mode 100644
index 0000000..66f5e05
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/dynamic-childlist-001-expected.txt
@@ -0,0 +1,47 @@
+This is a testharness.js-based test.
+PASS Adding missing children to mfrac
+PASS Removing child from valid mfrac
+PASS Adding child to valid mfrac
+PASS Removing extra child from mfrac
+PASS Adding missing children to munder
+PASS Removing child from valid munder
+PASS Adding child to valid munder
+PASS Removing extra child from munder
+PASS Adding missing children to mover
+PASS Removing child from valid mover
+PASS Adding child to valid mover
+PASS Removing extra child from mover
+PASS Adding missing children to munderover
+PASS Removing child from valid munderover
+PASS Adding child to valid munderover
+PASS Removing extra child from munderover
+PASS Adding missing children to msub
+PASS Removing child from valid msub
+PASS Adding child to valid msub
+PASS Removing extra child from msub
+PASS Adding missing children to msup
+PASS Removing child from valid msup
+PASS Adding child to valid msup
+PASS Removing extra child from msup
+PASS Adding missing children to msubsup
+PASS Removing child from valid msubsup
+PASS Adding child to valid msubsup
+PASS Removing extra child from msubsup
+PASS Adding missing children to mroot
+PASS Removing child from valid mroot
+PASS Adding child to valid mroot
+PASS Removing extra child from mroot
+PASS Removing children from msqrt
+PASS Adding children to msqrt
+PASS Removing children from mpadded
+PASS Adding children to mpadded
+PASS Removing children from mspace
+FAIL Adding children to mspace assert_approx_equals: inline position (child 0) expected -38 +/- 1 but got -8
+PASS multiscripts child count from 3 to 0
+PASS multiscripts child count from 3 to 1
+PASS multiscripts child count from 3 to 2
+PASS multiscripts child count from 0 to 3
+PASS multiscripts child count from 3 to 6
+PASS multiscripts child count from 3 to 8
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/dynamic-childlist-001.html b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/dynamic-childlist-001.html
new file mode 100644
index 0000000..8098c720
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/dynamic-childlist-001.html
@@ -0,0 +1,624 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Dynamic childlist of MathML elements</title>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#adjust-space-around-content-mpadded">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#dom-and-javascript">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#fractions-mfrac">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#prescripts-and-tensor-indices-mmultiscripts">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#radicals-msqrt-mroot">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#space-mspace">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+<meta name="assert" content="Dynamically modify DOM tree of some MathML elements by adding or removing children.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/layout-comparison.js"></script>
+<script>
+  function forceNumberOfChildren(element, count) {
+      while (element.children.length > count)
+          element.removeChild(element.lastElementChild);
+      for (let i = element.children.length; i < count; i++) {
+          if (element.tagName === "mmultiscripts" && i === 5) {
+              element.appendChild(FragmentHelper.createElement("mprescripts"));
+          } else {
+              let mspace = FragmentHelper.createElement("mspace");
+              mspace.setAttribute("width", `10px`);
+              mspace.setAttribute("height", `${10*(i+1)}px`);
+              mspace.setAttribute("style", `background: black;`);
+              element.appendChild(mspace);
+          }
+      }
+  }
+
+  setup({ explicit_done: true });
+  window.addEventListener("load", function() {
+      // force initial layout so we're sure what we're testing against
+      document.documentElement.getBoundingClientRect();
+
+      let reference = document.getElementById("reference");
+
+      Array.from(document.querySelectorAll("[data-title]")).forEach(element => {
+          test(function() {
+              assert_true(MathMLFeatureDetection.has_mspace());
+              let reference = document.getElementById(`${element.getAttribute("data-reference")}`);
+              forceNumberOfChildren(element, reference.children.length);
+              const epsilon = 1;
+              compareLayout(element, reference, epsilon);
+          }, `${element.getAttribute("data-title")}`);
+      });
+      done();
+  });
+</script>
+</head>
+<body>
+  <div id="log"></div>
+  <p>
+    <math>
+      <mfrac id="mfrac-reference-1">
+        <mspace width="10px" height="10px" style="background: black;"/>
+      </mfrac>
+      <mfrac id="mfrac-reference-2">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </mfrac>
+      <mfrac id="mfrac-reference-3">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </mfrac>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mfrac data-reference="mfrac-reference-2" data-title="Adding missing children to mfrac">
+      </mfrac>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mfrac data-reference="mfrac-reference-1" data-title="Removing child from valid mfrac">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </mfrac>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mfrac data-reference="mfrac-reference-3" data-title="Adding child to valid mfrac">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </mfrac>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mfrac data-reference="mfrac-reference-2" data-title="Removing extra child from mfrac">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </mfrac>
+    </math>
+  </p>
+  <hr/>
+  <p>
+    <math>
+      <munder id="munder-reference-1">
+        <mspace width="10px" height="10px" style="background: black;"/>
+      </munder>
+      <munder id="munder-reference-2">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </munder>
+      <munder id="munder-reference-3">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </munder>
+    </math>
+  </p>
+  <p>
+    <math>
+      <munder data-reference="munder-reference-2" data-title="Adding missing children to munder">
+      </munder>
+    </math>
+  </p>
+  <p>
+    <math>
+      <munder data-reference="munder-reference-1" data-title="Removing child from valid munder">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </munder>
+    </math>
+  </p>
+  <p>
+    <math>
+      <munder data-reference="munder-reference-3" data-title="Adding child to valid munder">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </munder>
+    </math>
+  </p>
+  <p>
+    <math>
+      <munder data-reference="munder-reference-2" data-title="Removing extra child from munder">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </munder>
+    </math>
+  </p>
+  <hr/>
+  <p>
+    <math>
+      <mover id="mover-reference-1">
+        <mspace width="10px" height="10px" style="background: black;"/>
+      </mover>
+      <mover id="mover-reference-2">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </mover>
+      <mover id="mover-reference-3">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </mover>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mover data-reference="mover-reference-2" data-title="Adding missing children to mover">
+      </mover>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mover data-reference="mover-reference-1" data-title="Removing child from valid mover">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </mover>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mover data-reference="mover-reference-3" data-title="Adding child to valid mover">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </mover>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mover data-reference="mover-reference-2" data-title="Removing extra child from mover">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </mover>
+    </math>
+  </p>
+  <hr/>
+  <p>
+    <math>
+      <munderover id="munderover-reference-2">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </munderover>
+      <munderover id="munderover-reference-3">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </munderover>
+      <munderover id="munderover-reference-4">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+        <mspace width="10px" height="40px" style="background: black;"/>
+      </munderover>
+    </math>
+  </p>
+  <p>
+    <math>
+      <munderover data-reference="munderover-reference-3" data-title="Adding missing children to munderover">
+      </munderover>
+    </math>
+  </p>
+  <p>
+    <math>
+      <munderover data-reference="munderover-reference-2" data-title="Removing child from valid munderover">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </munderover>
+    </math>
+  </p>
+  <p>
+    <math>
+      <munderover data-reference="munderover-reference-4" data-title="Adding child to valid munderover">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </munderover>
+    </math>
+  </p>
+  <p>
+    <math>
+      <munderover data-reference="munderover-reference-3" data-title="Removing extra child from munderover">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+        <mspace width="10px" height="40px" style="background: black;"/>
+      </munderover>
+    </math>
+  </p>
+  <hr/>
+  <p>
+    <math>
+      <msub id="msub-reference-1">
+        <mspace width="10px" height="10px" style="background: black;"/>
+      </msub>
+      <msub id="msub-reference-2">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </msub>
+      <msub id="msub-reference-3">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </msub>
+    </math>
+  </p>
+  <p>
+    <math>
+      <msub data-reference="msub-reference-2" data-title="Adding missing children to msub">
+      </msub>
+    </math>
+  </p>
+  <p>
+    <math>
+      <msub data-reference="msub-reference-1" data-title="Removing child from valid msub">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </msub>
+    </math>
+  </p>
+  <p>
+    <math>
+      <msub data-reference="msub-reference-3" data-title="Adding child to valid msub">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </msub>
+    </math>
+  </p>
+  <p>
+    <math>
+      <msub data-reference="msub-reference-2" data-title="Removing extra child from msub">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </msub>
+    </math>
+  </p>
+  <hr/>
+  <p>
+    <math>
+      <msup id="msup-reference-1">
+        <mspace width="10px" height="10px" style="background: black;"/>
+      </msup>
+      <msup id="msup-reference-2">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </msup>
+      <msup id="msup-reference-3">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </msup>
+    </math>
+  </p>
+  <p>
+    <math>
+      <msup data-reference="msup-reference-2" data-title="Adding missing children to msup">
+      </msup>
+    </math>
+  </p>
+  <p>
+    <math>
+      <msup data-reference="msup-reference-1" data-title="Removing child from valid msup">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </msup>
+    </math>
+  </p>
+  <p>
+    <math>
+      <msup data-reference="msup-reference-3" data-title="Adding child to valid msup">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </msup>
+    </math>
+  </p>
+  <p>
+    <math>
+      <msup data-reference="msup-reference-2" data-title="Removing extra child from msup">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </msup>
+    </math>
+  </p>
+  <hr/>
+  <p>
+    <math>
+      <msubsup id="msubsup-reference-2">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </msubsup>
+      <msubsup id="msubsup-reference-3">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </msubsup>
+      <msubsup id="msubsup-reference-4">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+        <mspace width="10px" height="40px" style="background: black;"/>
+      </msubsup>
+    </math>
+  </p>
+  <p>
+    <math>
+      <msubsup data-reference="msubsup-reference-3" data-title="Adding missing children to msubsup">
+      </msubsup>
+    </math>
+  </p>
+  <p>
+    <math>
+      <msubsup data-reference="msubsup-reference-2" data-title="Removing child from valid msubsup">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </msubsup>
+    </math>
+  </p>
+  <p>
+    <math>
+      <msubsup data-reference="msubsup-reference-4" data-title="Adding child to valid msubsup">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </msubsup>
+    </math>
+  </p>
+  <p>
+    <math>
+      <msubsup data-reference="msubsup-reference-3" data-title="Removing extra child from msubsup">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+        <mspace width="10px" height="40px" style="background: black;"/>
+      </msubsup>
+    </math>
+  </p>
+  <hr/>
+  <p>
+    <math>
+      <mroot id="mroot-reference-1">
+        <mspace width="10px" height="10px" style="background: black;"/>
+      </mroot>
+      <mroot id="mroot-reference-2">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </mroot>
+      <mroot id="mroot-reference-3">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </mroot>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mroot data-reference="mroot-reference-2" data-title="Adding missing children to mroot">
+      </mroot>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mroot data-reference="mroot-reference-1" data-title="Removing child from valid mroot">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </mroot>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mroot data-reference="mroot-reference-3" data-title="Adding child to valid mroot">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </mroot>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mroot data-reference="mroot-reference-2" data-title="Removing extra child from mroot">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </mroot>
+    </math>
+  </p>
+  <hr/>
+  <p>
+    <math>
+      <msqrt id="msqrt-reference-0">
+      </msqrt>
+      <msqrt id="msqrt-reference-2">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+       </msqrt>
+    </math>
+  </p>
+  <p>
+    <math>
+      <msqrt data-reference="msqrt-reference-0" data-title="Removing children from msqrt">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </msqrt>
+    </math>
+  </p>
+  <p>
+    <math>
+      <msqrt data-reference="msqrt-reference-2" data-title="Adding children to msqrt">
+        <mspace width="10px" height="10px" style="background: black;"/>
+      </msqrt>
+    </math>
+  </p>
+  <hr/>
+  <p>
+    <math>
+      <mpadded id="mpadded-reference-0">
+      </mpadded>
+      <mpadded id="mpadded-reference-2">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+       </mpadded>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mpadded data-reference="mpadded-reference-0" data-title="Removing children from mpadded">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </mpadded>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mpadded data-reference="mpadded-reference-2" data-title="Adding children to mpadded">
+        <mspace width="10px" height="10px" style="background: black;"/>
+      </mpadded>
+    </math>
+  </p>
+  <hr/>
+  <p>
+    <math>
+      <mspace id="mspace-reference-0" width="30px" height="70px" style="background: blue">
+      </mspace>
+      <mspace id="mspace-reference-2" width="30px" height="70px" style="background: green">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+       </mspace>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mspace data-reference="mspace-reference-0" data-title="Removing children from mspace" width="30px" height="70px" style="background: lightblue">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </mspace>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mspace data-reference="mspace-reference-2" data-title="Adding children to mspace" width="30px" height="70px" style="background: lightgreen">
+        <mspace width="10px" height="10px" style="background: black;"/>
+      </mspace>
+    </math>
+  </p>
+  <hr/>
+  <p>
+    <math>
+      <mmultiscripts id="mmultiscripts-reference-0">
+      </mmultiscripts>
+      <mmultiscripts id="mmultiscripts-reference-1">
+        <mspace width="10px" height="10px" style="background: black;"/>
+      </mmultiscripts>
+      <mmultiscripts id="mmultiscripts-reference-2">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+      </mmultiscripts>
+      <mmultiscripts id="mmultiscripts-reference-3">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </mmultiscripts>
+      <mmultiscripts id="mmultiscripts-reference-6">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+        <mspace width="10px" height="40px" style="background: black;"/>
+        <mspace width="10px" height="50px" style="background: black;"/>
+        <mprescripts/>
+      </mmultiscripts>
+      <mmultiscripts id="mmultiscripts-reference-8">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+        <mspace width="10px" height="40px" style="background: black;"/>
+        <mspace width="10px" height="50px" style="background: black;"/>
+        <mprescripts/>
+        <mspace width="10px" height="70px" style="background: black;"/>
+        <mspace width="10px" height="80px" style="background: black;"/>
+      </mmultiscripts>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mmultiscripts data-reference="mmultiscripts-reference-0" data-title="multiscripts child count from 3 to 0">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </mmultiscripts>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mmultiscripts data-reference="mmultiscripts-reference-1" data-title="multiscripts child count from 3 to 1">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </mmultiscripts>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mmultiscripts data-reference="mmultiscripts-reference-2" data-title="multiscripts child count from 3 to 2">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </mmultiscripts>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mmultiscripts data-reference="mmultiscripts-reference-3" data-title="multiscripts child count from 0 to 3">
+      </mmultiscripts>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mmultiscripts data-reference="mmultiscripts-reference-6" data-title="multiscripts child count from 3 to 6">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </mmultiscripts>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mmultiscripts data-reference="mmultiscripts-reference-8" data-title="multiscripts child count from 3 to 8">
+        <mspace width="10px" height="10px" style="background: black;"/>
+        <mspace width="10px" height="20px" style="background: black;"/>
+        <mspace width="10px" height="30px" style="background: black;"/>
+      </mmultiscripts>
+    </math>
+  </p>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-image/MediaStreamTrack-applyConstraints-getSettings.html b/third_party/blink/web_tests/external/wpt/mediacapture-image/MediaStreamTrack-applyConstraints-getSettings.html
index a1695b1..2ae3a87 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-image/MediaStreamTrack-applyConstraints-getSettings.html
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-image/MediaStreamTrack-applyConstraints-getSettings.html
@@ -131,9 +131,9 @@
   const constraints = [{ pan: 8 }, { tilt: 9 }];
   await Promise.all(constraints.map(async constraint =>
     promise_rejects_dom(
-        t, 'NotAllowedError',
+        t, 'NotSupportedError',
         videoTrack.applyConstraints({ advanced: [constraint] }),
-        "applyConstraints should throw a NotAllowedError for " +
+        "applyConstraints should throw a NotSupportedError for " +
         JSON.stringify(constraint))
   ));
 
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerlock/pointerevent_pointermove_in_pointerlock.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerlock/pointerevent_pointermove_in_pointerlock.html
index 3d8d47af..3cf59d8b 100644
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerlock/pointerevent_pointermove_in_pointerlock.html
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerlock/pointerevent_pointermove_in_pointerlock.html
@@ -45,67 +45,66 @@
                 innerframe.contentWindow.name = "innerframe";
                 phase = PhaseEnum.Start;
 
-                on_event(target0, "click", function(event) {
-                  target0.requestPointerLock();
-                });
+                on_event(target0, "click", (event)=>
+                  target0.requestPointerLock());
 
-                on_event(target1, "click", function(event) {
-                  target1.requestPointerLock();
-                });
+                on_event(target1, "click", (event)=>
+                  target1.requestPointerLock());
 
-                on_event(target0, "pointermove", function (event) {
+                on_event(target0, "pointermove", async (event)=> {
                   if (phase == PhaseEnum.Lock1) {
-                    assert_equals(document.pointerLockElement, target0);
-                    test_pointermove.step(function() {
+                    test_pointermove.step(()=> {
+                      assert_equals(document.pointerLockElement, target0);
                       assert_equals(event.view.name, "outerframe", "View attribute of pointermove should be the target frame.");
                     }, "View attribute of pointermove should be the target frame.");
                     document.exitPointerLock();
-                    actions_promise3 = actions_promise2.then( () => {
-                      // Click the inner frame target to lock.
-                      return clickInTarget("mouse", target1);
-                    });
+                    await actions_promise2;
+                    // Click the inner frame target to lock.
+                    actions_promise3 = clickInTarget("mouse", target1);
                   }
                 });
 
-                on_event(target1, "pointermove", function (event) {
+                on_event(target1, "pointermove", async (event)=> {
                   if (phase == PhaseEnum.Lock2) {
-                    assert_equals(innerframe.contentDocument.pointerLockElement, target1);
-                    test_pointermove.step(function() {
+                    test_pointermove.step(()=> {
+                      assert_equals(innerframe.contentDocument.pointerLockElement, target1);
                       assert_equals(event.view.name, "innerframe", "View attribute of pointermove should be the target frame.");
                     }, "View attribute of pointermove should be the target frame.");
                     innerframe.contentDocument.exitPointerLock();
-                    actions_promise4.then( () => {
-                      test_pointermove.done();
-                    });
+                    await actions_promise4;
+                    test_pointermove.done();
                   }
                 });
 
-                on_event(document, "pointerlockchange", function(event) {
+                on_event(document, "pointerlockchange", async (event)=> {
                   if (phase == PhaseEnum.Start) {
-                    assert_equals(document.pointerLockElement, target0);
+                    test_pointermove.step(()=>
+                      assert_equals(document.pointerLockElement, target0));
                     phase++;
-                    actions_promise2 = actions_promise1.then( () => {
-                      // Send moves in main frame target
-                      return new test_driver.Actions()
+                    await actions_promise1;
+                    // Send moves in main frame target
+                    actions_promise2 = new test_driver.Actions()
                                             .pointerMove(10, 30, {origin: target0})
                                             .send();
-                    });
                   }
                 });
 
-                on_event(innerframe.contentDocument, "pointerlockchange", function(event) {
+                on_event(innerframe.contentDocument, "pointerlockchange", async (event)=> {
                   if (phase == PhaseEnum.Lock1) {
-                    assert_equals(innerframe.contentDocument.pointerLockElement, target1);
+                    test_pointermove.step(()=>
+                      assert_equals(innerframe.contentDocument.pointerLockElement, target1));
                     phase++;
-                    actions_promise4 = actions_promise3.then( () => {
-                      // Send moves in inner frame target
-                      return new test_driver.Actions()
+                    await actions_promise3;
+                    // Send moves in inner frame target
+                    actions_promise4 = new test_driver.Actions()
                                             .pointerMove(10, 30, {origin: target0})
                                             .send();
-                    });
                   }
                 });
 
+                on_event(document, "pointerlockerror", test_pointermove.unreached_func("pointer lock request should not fail in document!"));
+                on_event(innerframe.contentDocument, "pointerlockerror", test_pointermove.unreached_func("pointer lock request should not fail in innerframe.contentDocument!"));
+
                 // Click the outer frame target to lock.
                 actions_promise1 = clickInTarget("mouse", target0);
             }
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-html-imports.https.html b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-html-imports.https.html
deleted file mode 100644
index 7a39fa8..0000000
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-html-imports.https.html
+++ /dev/null
@@ -1,65 +0,0 @@
-<!DOCTYPE html>
-<title>Service Worker: FetchEvent for HTMLImports</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/common/get-host-info.sub.js"></script>
-<script src="resources/test-helpers.sub.js"></script>
-<script>
-promise_test(function(t) {
-    var SCOPE = 'resources/fetch-request-html-imports-iframe.html';
-    var SCRIPT = 'resources/fetch-request-html-imports-worker.js';
-    var host_info = get_host_info();
-    return service_worker_unregister_and_register(t, SCRIPT, SCOPE)
-      .then(function(registration) {
-          t.add_cleanup(function() {
-              return service_worker_unregister(t, SCOPE);
-            });
-
-          return wait_for_state(t, registration.installing, 'activated');
-        })
-      .then(function() { return with_iframe(SCOPE); })
-      .then(function(frame) {
-          t.add_cleanup(function() {
-              frame.remove();
-            });
-          var same = frame.contentWindow.document.getElementById("same").import;
-          var same_same = same.getElementById("same-same").import;
-          var same_other = same.getElementById("same-other").import;
-          var other =
-              frame.contentWindow.document.getElementById("other").import;
-          var other_same = other.getElementById("other-same").import;
-          var other_other = other.getElementById("other-other").import;
-
-          assert_equals(
-              same.body.innerText,
-              'mode=cors credentials=same-origin',
-              'The request mode and credentials for same origin HTMLImport ' +
-              'must be set correctly.');
-          assert_equals(
-              same_same.body.innerText,
-              'mode=cors credentials=same-origin',
-              'The request mode and credentials for same origin HTMLImport ' +
-              'from same origin HTMLImports must be set correctly.');
-          assert_equals(
-              same_other.body.innerText,
-              'mode=cors credentials=same-origin',
-              'The request mode and credentials for other origin HTMLImport ' +
-              'from same origin HTMLImports must be set correctly.');
-          assert_equals(
-              other.body.innerText,
-              'mode=cors credentials=same-origin',
-              'The request mode and credentials for other origin HTMLImport ' +
-              'must be set correctly.');
-          assert_equals(
-              other_same.body.innerText,
-              'mode=cors credentials=same-origin',
-              'The request mode and credentials for same origin HTMLImport ' +
-              'from other origin HTMLImports must be set correctly.');
-          assert_equals(
-              other_other.body.innerText,
-              'mode=cors credentials=same-origin',
-              'The request mode and credentials for other origin HTMLImport ' +
-              'from other origin HTMLImport must be set correctly.');
-        });
-  }, 'Verify the FetchEvent for HTMLImports');
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/tools/ci/ci_wpt.sh b/third_party/blink/web_tests/external/wpt/tools/ci/ci_tools_integration_test.sh
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/tools/ci/ci_wpt.sh
rename to third_party/blink/web_tests/external/wpt/tools/ci/ci_tools_integration_test.sh
diff --git a/third_party/blink/web_tests/external/wpt/tools/ci/tc/tasks/test.yml b/third_party/blink/web_tests/external/wpt/tools/ci/tc/tasks/test.yml
index 318437a..3fae9ea 100644
--- a/third_party/blink/web_tests/external/wpt/tools/ci/tc/tasks/test.yml
+++ b/third_party/blink/web_tests/external/wpt/tools/ci/tc/tasks/test.yml
@@ -347,14 +347,14 @@
         run-job:
           - tools_unittest
 
-  - tools/wpt/ tests (Python 2):
+  - tools/ integration tests (Python 2):
       description: >-
-        Integration tests for wpt commands
+        Integration tests for tools running under Python 2.7
       use:
         - wpt-base
         - trigger-pr
         - tox-python2
-      command: ./tools/ci/ci_wpt.sh
+      command: ./tools/ci/ci_tools_integration_test.sh
       install:
         - libnss3-tools
       options:
@@ -369,14 +369,14 @@
         run-job:
           - wpt_integration
 
-  - tools/wpt/ tests (Python 3.6):
+  - tools/ integration tests (Python 3.6):
       description: >-
-        Integration tests for wpt commands
+        Integration tests for tools running under Python 3.6
       use:
         - wpt-base
         - trigger-pr
         - tox-python3
-      command: ./tools/ci/ci_wpt.sh
+      command: ./tools/ci/ci_tools_integration_test.sh
       install:
         - libnss3-tools
       options:
@@ -391,14 +391,14 @@
         run-job:
           - wpt_integration
 
-  - tools/wpt/ tests (Python 3.8):
+  - tools/ integration tests (Python 3.8):
       description: >-
-        Integration tests for wpt commands
+        Integration tests for tools running under Python 3.8
       use:
         - wpt-base
         - trigger-pr
         - tox-python38
-      command: ./tools/ci/ci_wpt.sh
+      command: ./tools/ci/ci_tools_integration_test.sh
       install:
         - libnss3-tools
       options:
diff --git a/third_party/blink/web_tests/external/wpt/tools/ci/tc/tests/test_valid.py b/third_party/blink/web_tests/external/wpt/tools/ci/tc/tests/test_valid.py
index 47cbc2e..acfe875 100644
--- a/third_party/blink/web_tests/external/wpt/tools/ci/tc/tests/test_valid.py
+++ b/third_party/blink/web_tests/external/wpt/tools/ci/tc/tests/test_valid.py
@@ -134,9 +134,9 @@
       'tools/ unittests (Python 2)',
       'tools/ unittests (Python 3.6)',
       'tools/ unittests (Python 3.8)',
-      'tools/wpt/ tests (Python 2)',
-      'tools/wpt/ tests (Python 3.6)',
-      'tools/wpt/ tests (Python 3.8)',
+      'tools/ integration tests (Python 2)',
+      'tools/ integration tests (Python 3.6)',
+      'tools/ integration tests (Python 3.8)',
       'resources/ tests',
       'infrastructure/ tests',
       'infrastructure/ tests (Python 3)'}),
diff --git a/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt b/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt
index 988ffe8..857c788 100644
--- a/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt
+++ b/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt
@@ -1,3 +1,3 @@
-mypy==0.770
+mypy==0.780
 mypy-extensions==0.4.3
 typed-ast==1.4.1
diff --git a/third_party/blink/web_tests/external/wpt/tools/third_party/atomicwrites/docs/make.bat b/third_party/blink/web_tests/external/wpt/tools/third_party/atomicwrites/docs/make.bat
old mode 100644
new mode 100755
diff --git a/third_party/blink/web_tests/external/wpt/tools/third_party/h2/docs/make.bat b/third_party/blink/web_tests/external/wpt/tools/third_party/h2/docs/make.bat
old mode 100644
new mode 100755
diff --git a/third_party/blink/web_tests/external/wpt/tools/third_party/html5lib/doc/make.bat b/third_party/blink/web_tests/external/wpt/tools/third_party/html5lib/doc/make.bat
old mode 100644
new mode 100755
diff --git a/third_party/blink/web_tests/external/wpt/tools/third_party/more-itertools/docs/make.bat b/third_party/blink/web_tests/external/wpt/tools/third_party/more-itertools/docs/make.bat
old mode 100644
new mode 100755
diff --git a/third_party/blink/web_tests/external/wpt/tools/third_party/pytest/scripts/call-tox.bat b/third_party/blink/web_tests/external/wpt/tools/third_party/pytest/scripts/call-tox.bat
old mode 100644
new mode 100755
diff --git a/third_party/blink/web_tests/external/wpt/tools/third_party/pytest/scripts/install-pypy.bat b/third_party/blink/web_tests/external/wpt/tools/third_party/pytest/scripts/install-pypy.bat
old mode 100644
new mode 100755
diff --git a/third_party/blink/web_tests/external/wpt/web-bundle/subresource-loading/link-web-bundle.tentative.html b/third_party/blink/web_tests/external/wpt/web-bundle/subresource-loading/link-web-bundle.tentative.html
new file mode 100644
index 0000000..a4d1e70
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/web-bundle/subresource-loading/link-web-bundle.tentative.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<title>A link element with rel="webbundle"</title>
+<link
+  rel="help"
+  href="https://github.com/WICG/webpackage/blob/master/explainers/subresource-loading.md"
+/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+  <link id="link_empty" />
+  <link id="link_web_bundle_1" rel="webbundle" />
+  <link id="link_web_bundle_2" rel="webbundle" resources="foo" />
+  <script>
+    test(() => {
+      assert_false(
+        "resources" in Element.prototype,
+        "resources must not be defined on Element prototype"
+      );
+      assert_true(
+        "resources" in HTMLLinkElement.prototype,
+        "resources must be defined on HTMLLinkElement prototype"
+      );
+    }, "resources must be defined on HTMLLinkElement prototype");
+
+    test(() => {
+      const link = document.createElement("link");
+      assert_true(link.relList.supports("webbundle"));
+    }, "webbundle must be a supported token of a link element's relList");
+
+    test(() => {
+      const link_web_bundle = document.querySelector("#link_web_bundle_1");
+      assert_equals(
+        link_web_bundle.getAttribute("rel"),
+        "webbundle",
+        "rel attribute must return webbundle"
+      );
+      assert_true(
+        link_web_bundle.relList.contains("webbundle"),
+        "relList must contain webbundle for <link rel=webbundle>."
+      );
+      assert_false(
+        document.querySelector("#link_empty").relList.contains("webbundle"),
+        "relList must not contain webbundle for <link>"
+      );
+    }, "relList must contain webbundle if rel attribute contains it");
+
+    test(() => {
+      assert_equals(
+        document.querySelector("#link_web_bundle_1").getAttribute("resources"),
+        null,
+        "resources attribute must return null when the attribute is not given"
+      );
+      assert_equals(
+        document.querySelector("#link_web_bundle_2").getAttribute("resources"),
+        "foo",
+        "resources attribute must return the specified value"
+      );
+      // TODO: Test more variant of resoruces attribute values.
+    }, "resoruces attribute must return null or specified value");
+  </script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/web-bundle/wbn-location.tentative.html b/third_party/blink/web_tests/external/wpt/web-bundle/wbn-from-network/wbn-location.tentative.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/web-bundle/wbn-location.tentative.html
rename to third_party/blink/web_tests/external/wpt/web-bundle/wbn-from-network/wbn-location.tentative.html
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-1-chan.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-1-chan.html
index dbd146d4d..300b436 100644
--- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-1-chan.html
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-1-chan.html
@@ -191,11 +191,16 @@
             description: '5.1->2 explicit downmix producing 2-channel output'
           },
           (task, should) => {
+            // Scale tolerance by maximum amplitude expected in down-mix
+            // output.
+            let threshold = (1.0 + Math.sqrt(0.5) * 2) * absoluteThreshold;
+
             downMixTest(
                 {
                   channelCountMode: 'explicit',
                   numberOfInputs: 6,
-                  prefix: '5.1 chan downmix explicit'
+                  prefix: '5.1 chan downmix explicit',
+                  absoluteThreshold: threshold
                 },
                 should)
                 .then(() => task.done());
@@ -219,11 +224,11 @@
                   should(out0.slice(1), '1->2 explicit upmix: channel 0')
                       .beCloseToArray(
                           input.slice(0, length - 1),
-                          {absoluteThreshold: 3.577e-7});
+                          {absoluteThreshold: absoluteThreshold});
                   should(out1.slice(1), '1->2 explicit upmix: channel 1')
                       .beCloseToArray(
                           input.slice(0, length - 1),
-                          {absoluteThreshold: 3.577e-7});
+                          {absoluteThreshold: absoluteThreshold});
                 })
                 .then(() => task.done());
           });
@@ -247,7 +252,7 @@
                   should(out0.slice(1), '1->2 clamped-max upmix: channel 0')
                       .beCloseToArray(
                           input.slice(0, length - 1),
-                          {absoluteThreshold: 3.577e-7});
+                          {absoluteThreshold: absoluteThreshold});
                   should(out1, '1->2 clamped-max upmix: channel 1')
                       .beConstantValueOf(0);
                 })
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-2-chan.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-2-chan.html
index 2d24236..9baf5f9 100644
--- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-2-chan.html
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-2-chan.html
@@ -116,8 +116,7 @@
             stereoResponseExplicitTest(
                 {
                   numberOfInputes: 2,
-                  prefix: '2-in explicit mode',
-                  absoluteThresholds: [0, 0]
+                  prefix: '2-in explicit mode'
                 },
                 should)
                 .then(() => task.done());
@@ -126,14 +125,13 @@
       audit.define(
           {
             label: '3-channel input explicit mode',
-            description: '3->2 downmix producing 2-channel output'
+            description: '3->1 downmix producing 2-channel output'
           },
           (task, should) => {
             stereoResponseExplicitTest(
                 {
                   numberOfInputs: 3,
-                  prefix: '3-in explicit',
-                  absoluteThresholds: [0, 0]
+                  prefix: '3-in explicit'
                 },
                 should)
                 .then(() => task.done());
@@ -142,14 +140,13 @@
       audit.define(
           {
             label: '4-channel input explicit mode',
-            description: '4->2 downmix producing 2-channel output'
+            description: '4->1 downmix producing 2-channel output'
           },
           (task, should) => {
             stereoResponseExplicitTest(
                 {
                   numberOfInputs: 4,
-                  prefix: '4-in explicit',
-                  absoluteThresholds: [3.5763e-7, 2.9803e-7]
+                  prefix: '4-in explicit'
                 },
                 should)
                 .then(() => task.done());
@@ -158,11 +155,20 @@
       audit.define(
           {
             label: '5.1-channel input explicit mode',
-            description: '5.1->2 downmix producing 2-channel output'
+            description: '5.1->1 downmix producing 2-channel output'
           },
           (task, should) => {
-            stereoResponseTest({numberOfInputs: 6, prefix: '5.1-in explicit', absoluteThresholds:
-            [0, 0]}, should)
+            // Scale tolerance by maximum amplitude expected in down-mix
+            // output.
+            let threshold = (Math.sqrt(0.5) * 2 + 2.0) * absoluteThreshold;
+
+            stereoResponseExplicitTest(
+                {
+                  numberOfInputs: 6,
+                  prefix: '5.1-in explicit',
+                  absoluteThreshold: threshold
+                },
+                should)
                 .then(() => task.done());
           });
 
@@ -349,16 +355,15 @@
           let expected0 = audioBuffer.getChannelData(2);
           let expected1 = audioBuffer.getChannelData(3);
 
+          let threshold = options.absoluteThreshold ?
+              options.absoluteThreshold : absoluteThreshold;
+
           // Verify that each output channel of the convolver matches
           // the delayed signal from the reference
           should(actual0, options.prefix + ': Channel 0')
-              .beCloseToArray(
-                  expected0,
-                  {absoluteThreshold: options.absoluteThresholds[0]});
+              .beCloseToArray(expected0, {absoluteThreshold: threshold});
           should(actual1, options.prefix + ': Channel 1')
-              .beCloseToArray(
-                  expected1,
-                  {absoluteThreshold: options.absoluteThresholds[1]});
+              .beCloseToArray(expected1, {absoluteThreshold: threshold});
         });
       }
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-extensions/RTCRtpSynchronizationSource-captureTimestamp-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-extensions/RTCRtpSynchronizationSource-captureTimestamp-expected.txt
new file mode 100644
index 0000000..e2df6c1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc-extensions/RTCRtpSynchronizationSource-captureTimestamp-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught SyntaxError: Unexpected string
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-stats/getStats-remote-candidate-address-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-stats/getStats-remote-candidate-address-expected.txt
index a18cda0..e2df6c1 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-stats/getStats-remote-candidate-address-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc-stats/getStats-remote-candidate-address-expected.txt
@@ -1,5 +1,4 @@
 This is a testharness.js-based test.
-FAIL Do not expose in stats remote addresses that are not known to be already exposed to JS assert_equals: address should be null expected (object) null but got (undefined) undefined
-PASS Expose in stats remote addresses that are already exposed to JS
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught SyntaxError: Unexpected string
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt
index 126a223..e2df6c1 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt
@@ -1,16 +1,4 @@
 This is a testharness.js-based test.
-PASS getStats() with no argument should succeed
-PASS getStats(null) should succeed
-PASS getStats() with track not added to connection should reject with InvalidAccessError
-PASS getStats() with track added via addTrack should succeed
-PASS getStats() with track added via addTransceiver should succeed
-PASS getStats() with track associated with more than one sender should reject with InvalidAccessError
-PASS getStats() with track associated with both sender and receiver should reject with InvalidAccessError
-PASS getStats() with no argument should return stats report containing peer-connection stats on an empty PC
-FAIL getStats() with no argument should return stats report containing peer-connection stats and outbound-track-stats assert_true: Expect statsReport to contain stats object of type outbound-rtp expected true got false
-FAIL getStats() with no argument should return stats for no-stream tracks assert_true: Expect statsReport to contain stats object of type outbound-rtp expected true got false
-FAIL getStats() on track associated with RtpSender should return stats report containing outbound-rtp stats assert_equals: Expect dictionary.remoteId to be string expected "string" but got "undefined"
-FAIL getStats() on track associated with RtpReceiver should return stats report containing inbound-rtp stats assert_equals: Expect dictionary.codecId to be string expected "string" but got "undefined"
-FAIL getStats() with connected peer connections having tracks and data channel should return all mandatory to implement stats assert_unreached: test failed with error: Error: assert_true: Expect dictionary.dataChannelIdentifier to be integer expected true got false Reached unreachable code
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught SyntaxError: Unexpected string
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-getStats.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-getStats.https.html
index 2ecb21d..bdf7770 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-getStats.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-getStats.https.html
@@ -144,8 +144,8 @@
       return pc.getStats();
     })
     .then(statsReport => {
-      validateStatsReport(statsReport);
-      assert_stats_report_has_stats(statsReport, ['peer-connection']);
+//      validateStatsReport(statsReport);
+//      assert_stats_report_has_stats(statsReport, ['peer-connection']);
       assert_stats_report_has_stats(statsReport, ['outbound-rtp']);
     });
   }, 'getStats() with no argument should return stats report containing peer-connection stats and outbound-track-stats');
@@ -212,8 +212,7 @@
         pc2.getReceivers()[0].track.addEventListener('unmute', resolve);
       });
     }
-    const receivedTrack = pc2.getReceivers()[0].track;
-    const stats = await pc2.getStats(receivedTrack);
+    const stats = await pc2.getStats(pc2.getReceivers()[0].track);
     validateStatsReport(stats);
     assert_stats_report_has_stats(stats, ['inbound-rtp']);
   }, `getStats() on track associated with RtpReceiver should return stats report containing inbound-rtp stats`);
@@ -233,8 +232,6 @@
     "remote-outbound-rtp",
     "peer-connection",
     "data-channel",
-    "stream",
-    "track",
     "transport",
     "candidate-pair",
     "local-candidate",
@@ -277,6 +274,7 @@
 
         assert_equals(dataChannelStats.label, 'test-channel');
 
+        /* TODO track stats are obsolete - replace with sender/receiver? */
         const audioTrackStats = findStatsFromReport(statsReport,
           stats => {
             return stats.type === 'track' &&
@@ -295,13 +293,6 @@
 
         assert_equals(videoTrackStats.kind, 'video');
 
-        const mediaStreamStats = findStatsFromReport(statsReport,
-          stats => {
-            return stats.type === 'stream' &&
-              stats.streamIdentifier === mediaStream.id;
-          },
-          'Expect media stream stats to be found');
-
         assert_true(mediaStreamStats.trackIds.include(audioTrackStats.id));
         assert_true(mediaStreamStats.trackIds.include(videoTrackStats.id));
       }
@@ -310,6 +301,7 @@
         // Wait a while for the peer connections to collect stats
         t.step_timeout(() => {
           Promise.all([
+            /* TODO: for both pc1 and pc2 to expose all mandatory stats, they need to both send/receive tracks and data channels */
             pc1.getStats()
             .then(statsReport => testStatsReport(pc1, statsReport)),
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt
index 1256301..e2df6c1 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt
@@ -1,80 +1,4 @@
 This is a testharness.js-based test.
-Found 76 tests; 51 PASS, 25 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS getStats succeeds
-PASS RTCRtpStreamStats's ssrc
-PASS RTCRtpStreamStats's kind
-PASS RTCRtpStreamStats's transportId
-PASS RTCRtpStreamStats's codecId
-PASS RTCReceivedRtpStreamStats's packetsReceived
-PASS RTCReceivedRtpStreamStats's packetsLost
-PASS RTCReceivedRtpStreamStats's jitter
-FAIL RTCReceivedRtpStreamStats's packetsDiscarded assert_true: Is packetsDiscarded present expected true got false
-PASS RTCInboundRtpStreamStats's trackId
-FAIL RTCInboundRtpStreamStats's receiverId assert_true: Is receiverId present expected true got false
-FAIL RTCInboundRtpStreamStats's remoteId assert_true: Is remoteId present expected true got false
-PASS RTCInboundRtpStreamStats's framesDecoded
-PASS RTCRemoteInboundRtpStreamStats's localId
-PASS RTCRemoteInboundRtpStreamStats's roundTripTime
-PASS RTCSentRtpStreamStats's packetsSent
-PASS RTCSentRtpStreamStats's bytesSent
-PASS RTCOutboundRtpStreamStats's trackId
-FAIL RTCOutboundRtpStreamStats's senderId assert_true: Is senderId present expected true got false
-PASS RTCOutboundRtpStreamStats's remoteId
-PASS RTCOutboundRtpStreamStats's framesEncoded
-FAIL RTCRemoteOutboundRtpStreamStats's localId assert_true: Is localId present expected true got false
-FAIL RTCRemoteOutboundRtpStreamStats's remoteTimestamp assert_true: Is remoteTimestamp present expected true got false
-PASS RTCPeerConnectionStats's dataChannelsOpened
-PASS RTCPeerConnectionStats's dataChannelsClosed
-PASS RTCDataChannelStats's protocol
-FAIL RTCDataChannelStats's dataChannelIdentifier assert_true: Is dataChannelIdentifier present expected true got false
-PASS RTCDataChannelStats's state
-PASS RTCDataChannelStats's messagesSent
-PASS RTCDataChannelStats's bytesSent
-PASS RTCDataChannelStats's messagesReceived
-PASS RTCDataChannelStats's bytesReceived
-FAIL RTCMediaStreamStats's streamIdentifer assert_true: Is streamIdentifer present expected true got false
-PASS RTCMediaStreamStats's trackIds
-FAIL RTCMediaHandlerStats's trackIdentifier assert_true: Is trackIdentifier present expected true got false
-FAIL RTCMediaHandlerStats's remoteSource assert_true: Is remoteSource present expected true got false
-FAIL RTCMediaHandlerStats's ended assert_true: Is ended present expected true got false
-FAIL RTCAudioHandlerStats's audioLevel assert_true: Is audioLevel present expected true got false
-FAIL RTCVideoHandlerStats's frameWidth assert_true: Is frameWidth present expected true got false
-FAIL RTCVideoHandlerStats's frameHeight assert_true: Is frameHeight present expected true got false
-FAIL RTCVideoHandlerStats's framesPerSecond assert_true: Is framesPerSecond present expected true got false
-FAIL RTCVideoSenderStats's framesSent assert_true: Is framesSent present expected true got false
-FAIL RTCVideoReceiverStats's framesReceived assert_true: Is framesReceived present expected true got false
-FAIL RTCVideoReceiverStats's framesDecoded assert_true: Is framesDecoded present expected true got false
-FAIL RTCVideoReceiverStats's framesDropped assert_true: Is framesDropped present expected true got false
-FAIL RTCVideoReceiverStats's partialFramesLost assert_true: Is partialFramesLost present expected true got false
-PASS RTCCodecStats's payloadType
-FAIL RTCCodecStats's codecType assert_true: Is codecType present expected true got false
-PASS RTCCodecStats's clockRate
-PASS RTCCodecStats's channels
-PASS RTCCodecStats's sdpFmtpLine
-PASS RTCTransportStats's bytesSent
-PASS RTCTransportStats's bytesReceived
-FAIL RTCTransportStats's rtcpTransportStatsId assert_true: Is rtcpTransportStatsId present expected true got false
-PASS RTCTransportStats's selectedCandidatePairId
-PASS RTCTransportStats's localCertificateId
-PASS RTCTransportStats's remoteCertificateId
-PASS RTCIceCandidatePairStats's transportId
-PASS RTCIceCandidatePairStats's localCandidateId
-PASS RTCIceCandidatePairStats's remoteCandidateId
-PASS RTCIceCandidatePairStats's state
-PASS RTCIceCandidatePairStats's priority
-PASS RTCIceCandidatePairStats's nominated
-PASS RTCIceCandidatePairStats's bytesSent
-PASS RTCIceCandidatePairStats's bytesReceived
-PASS RTCIceCandidatePairStats's totalRoundTripTime
-PASS RTCIceCandidatePairStats's currentRoundTripTime
-FAIL RTCIceCandidateStats's address assert_true: Is address present expected true got false
-PASS RTCIceCandidateStats's port
-PASS RTCIceCandidateStats's protocol
-PASS RTCIceCandidateStats's candidateType
-FAIL RTCIceCandidateStats's url assert_true: Is url present expected true got false
-PASS RTCCertificateStats's fingerprint
-PASS RTCCertificateStats's fingerprintAlgorithm
-PASS RTCCertificateStats's base64Certificate
-FAIL RTCCertificateStats's issuerCertificateId assert_true: Is issuerCertificateId present expected true got false
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught SyntaxError: Unexpected string
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-track-stats.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-track-stats.https-expected.txt
index bd8e844..e2df6c1 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-track-stats.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-track-stats.https-expected.txt
@@ -1,21 +1,4 @@
 This is a testharness.js-based test.
-PASS addTrack() without setLocalDescription() yields track stats
-PASS addTrack() without setLocalDescription() yields media stream stats
-PASS addTrack() with setLocalDescription() yields track stats
-PASS addTrack() with setLocalDescription() yields media stream stats
-PASS addTrack(): Media stream stats references track stats
-PASS Media stream stats references track stats
-PASS O/A exchange yields outbound RTP stream stats for sending track
-PASS O/A exchange yields inbound RTP stream stats for receiving track
-PASS replaceTrack() before offer: new track attachment stats present
-PASS replaceTrack() after offer, before answer: new track attachment stats present
-PASS replaceTrack() after answer: new track attachment stats present
-FAIL replaceTrack(): original track attachment stats present after replacing assert_true: Has stats for original track expected true got false
-PASS RTCRtpSender.getStats() contains only outbound-rtp and related stats
-PASS RTCRtpReceiver.getStats() contains only inbound-rtp and related stats
-PASS RTCPeerConnection.getStats(sendingTrack) is the same as RTCRtpSender.getStats()
-PASS RTCPeerConnection.getStats(receivingTrack) is the same as RTCRtpReceiver.getStats()
-PASS RTCPeerConnection.getStats(track) throws InvalidAccessError when there are zero senders or receivers for the track
-PASS RTCPeerConnection.getStats(track) throws InvalidAccessError when there are multiple senders for the track
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught SyntaxError: Unexpected string
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt
index 002ae802..e2df6c1 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt
@@ -1,5 +1,4 @@
 This is a testharness.js-based test.
-FAIL receiver.getStats() via addTransceiver should return stats report containing inbound-rtp stats assert_equals: Expect dictionary.codecId to be string expected "string" but got "undefined"
-FAIL receiver.getStats() via addTrack should return stats report containing inbound-rtp stats assert_equals: Expect dictionary.codecId to be string expected "string" but got "undefined"
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught SyntaxError: Unexpected string
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpSender-getStats.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpSender-getStats.https-expected.txt
index f7302af8..e2df6c1 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpSender-getStats.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpSender-getStats.https-expected.txt
@@ -1,5 +1,4 @@
 This is a testharness.js-based test.
-FAIL sender.getStats() via addTransceiver should return stats report containing outbound-rtp stats assert_equals: Expect dictionary.remoteId to be string expected "string" but got "undefined"
-FAIL sender.getStats() via addTrack should return stats report containing outbound-rtp stats assert_equals: Expect dictionary.remoteId to be string expected "string" but got "undefined"
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught SyntaxError: Unexpected string
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCStats-helper.js b/third_party/blink/web_tests/external/wpt/webrtc/RTCStats-helper.js
index 5cd7d2c9..7bebc2e 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCStats-helper.js
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCStats-helper.js
@@ -1,4 +1,4 @@
-'use strict';
+R'use strict';
 
 // Test is based on the following editor draft:
 // webrtc-pc 20171130
@@ -25,7 +25,8 @@
       "candidate-pair",
       "local-candidate",
       "remote-candidate",
-      "certificate"
+      "certificate",
+      "ice-server"
     };
  */
 const statsValidatorTable = {
@@ -34,16 +35,19 @@
   'outbound-rtp': validateOutboundRtpStreamStats,
   'remote-inbound-rtp': validateRemoteInboundRtpStreamStats,
   'remote-outbound-rtp': validateRemoteOutboundRtpStreamStats,
+  'media-source': validateMediaSourceStats,
   'csrc': validateContributingSourceStats,
   'peer-connection': validatePeerConnectionStats,
   'data-channel': validateDataChannelStats,
-  'stream': validateMediaStreamStats,
-  'track': validateMediaStreamTrackStats,
+  'transceiver': validateTransceiverStats,
+  'sender': validateSenderStats,
+  'receiver': validateReceiverStats,
   'transport': validateTransportStats,
   'candidate-pair': validateIceCandidatePairStats,
   'local-candidate': validateIceCandidateStats,
   'remote-candidate': validateIceCandidateStats,
-  'certificate': validateCertificateStats
+  'certificate': validateCertificateStats,
+  'ice-server': validateIceServerStats
 };
 
 // Validate that the stats objects in a stats report
@@ -143,44 +147,31 @@
 
 /*
   [webrtc-stats]
-  7.1.  RTCRTPStreamStats dictionary
-    dictionary RTCRTPStreamStats : RTCStats {
-      unsigned long      ssrc;
-      DOMString          mediaType;
-      DOMString          trackId;
-      DOMString          transportId;
-      DOMString          codecId;
-      unsigned long      firCount;
-      unsigned long      pliCount;
-      unsigned long      nackCount;
-      unsigned long      sliCount;
-      unsigned long long qpSum;
+  7.1.  RTCRtpStreamStats dictionary
+    dictionary RTCRtpStreamStats : RTCStats {
+      unsigned long       ssrc;
+      DOMString           kind;
+      DOMString           transportId;
+      DOMString           codecId;
     };
 
-    mediaType of type DOMString
+    kind of type DOMString
       Either "audio" or "video".
 
   [webrtc-pc]
   8.6.  Mandatory To Implement Stats
-    - RTCRTPStreamStats, with attributes ssrc, mediaType, trackId,
-      transportId, codecId, nackCount
+    - RTCRtpStreamStats, with attributes ssrc, kind, transportId, codecId
  */
 function validateRtpStreamStats(statsReport, stats) {
   validateRtcStats(statsReport, stats);
 
   assert_unsigned_int_field(stats, 'ssrc');
-  assert_string_field(stats, 'mediaType');
-  assert_enum_field(stats, 'mediaType', ['audio', 'video'])
+  assert_string_field(stats, 'kind');
+  assert_enum_field(stats, 'kind', ['audio', 'video'])
 
-  validateIdField(statsReport, stats, 'trackId', 'track');
   validateIdField(statsReport, stats, 'transportId', 'transport');
   validateIdField(statsReport, stats, 'codecId', 'codec');
 
-  assert_optional_unsigned_int_field(stats, 'firCount');
-  assert_optional_unsigned_int_field(stats, 'pliCount');
-  assert_optional_unsigned_int_field(stats, 'nackCount');
-  assert_optional_unsigned_int_field(stats, 'sliCount');
-  assert_optional_unsigned_int_field(stats, 'qpSum');
 }
 
 /*
@@ -194,7 +185,6 @@
       unsigned long clockRate;
       unsigned long channels;
       DOMString     sdpFmtpLine;
-      DOMString     implementation;
     };
 
     enum RTCCodecType {
@@ -204,65 +194,63 @@
 
   [webrtc-pc]
   8.6.  Mandatory To Implement Stats
-    - RTCCodecStats, with attributes payloadType, codec, clockRate, channels, sdpFmtpLine
+    - RTCCodecStats, with attributes payloadType, codecType, mimeType, clockRate, channels, sdpFmtpLine
  */
 
 function validateCodecStats(statsReport, stats) {
   validateRtcStats(statsReport, stats);
 
   assert_unsigned_int_field(stats, 'payloadType');
-  assert_optional_enum_field(stats, 'codecType', ['encode', 'decode']);
+  assert_enum_field(stats, 'codecType', ['encode', 'decode']);
 
   validateOptionalIdField(statsReport, stats, 'transportId', 'transport');
 
-  assert_optional_string_field(stats, 'mimeType');
+  assert_string_field(stats, 'mimeType');
   assert_unsigned_int_field(stats, 'clockRate');
-  assert_optional_unsigned_int_field(stats, 'channels');
+  assert_unsigned_int_field(stats, 'channels');
 
-  assert_optional_string_field(stats, 'sdpFmtpLine');
-  assert_optional_string_field(stats, 'implementation');
+  assert_string_field(stats, 'sdpFmtpLine');
 }
 
 /*
   [webrtc-stats]
-  7.3.  RTCReceivedRTPStreamStats dictionary
-    dictionary RTCReceivedRTPStreamStats : RTCRTPStreamStats {
-        unsigned long      packetsReceived;
-        unsigned long long bytesReceived;
-        long               packetsLost;
-        double             jitter;
-        double             fractionLost;
-        unsigned long      packetsDiscarded;
-        unsigned long      packetsFailedDecryption;
-        unsigned long      packetsRepaired;
-        unsigned long      burstPacketsLost;
-        unsigned long      burstPacketsDiscarded;
-        unsigned long      burstLossCount;
-        unsigned long      burstDiscardCount;
-        double             burstLossRate;
-        double             burstDiscardRate;
-        double             gapLossRate;
-        double             gapDiscardRate;
+  7.3.  RTCReceivedRtpStreamStats dictionary
+    dictionary RTCReceivedRtpStreamStats : RTCRtpStreamStats {
+      unsigned long long   packetsReceived;
+      long long            packetsLost;
+      double               jitter;
+      unsigned long long   packetsDiscarded;
+      unsigned long long   packetsRepaired;
+      unsigned long long   burstPacketsLost;
+      unsigned long long   burstPacketsDiscarded;
+      unsigned long        burstLossCount;
+      unsigned long        burstDiscardCount;
+      double               burstLossRate;
+      double               burstDiscardRate;
+      double               gapLossRate;
+      double               gapDiscardRate;
+      unsigned long        framesDropped;
+      unsigned long        partialFramesLost;
+      unsigned long        fullFramesLost;
     };
 
     [webrtc-pc]
     8.6.  Mandatory To Implement Stats
-      - RTCReceivedRTPStreamStats, with all required attributes from its
+      - RTCReceivedRtpStreamStats, with all required attributes from its
         inherited dictionaries, and also attributes packetsReceived,
-        bytesReceived, packetsLost, jitter, packetsDiscarded
+        packetsLost, jitter, packetsDiscarded, framesDropped
  */
 function validateReceivedRtpStreamStats(statsReport, stats) {
   validateRtpStreamStats(statsReport, stats);
 
   assert_unsigned_int_field(stats, 'packetsReceived');
-  assert_unsigned_int_field(stats, 'bytesReceived');
   assert_unsigned_int_field(stats, 'packetsLost');
 
   assert_number_field(stats, 'jitter');
-  assert_optional_number_field(stats, 'fractionLost');
 
   assert_unsigned_int_field(stats, 'packetsDiscarded');
-  assert_optional_unsigned_int_field(stats, 'packetsFailedDecryption');
+  assert_unsigned_int_field(stats, 'framesDropped');
+
   assert_optional_unsigned_int_field(stats, 'packetsRepaired');
   assert_optional_unsigned_int_field(stats, 'burstPacketsLost');
   assert_optional_unsigned_int_field(stats, 'burstPacketsDiscarded');
@@ -273,41 +261,143 @@
   assert_optional_number_field(stats, 'burstDiscardRate');
   assert_optional_number_field(stats, 'gapLossRate');
   assert_optional_number_field(stats, 'gapDiscardRate');
+
+  assert_optional_unsigned_int_field(stats, 'partialFramesLost');
+  assert_optional_unsigned_int_field(stats, 'fullFramesLost');
 }
 
 /*
   [webrtc-stats]
-  7.4.  RTCInboundRTPStreamStats dictionary
-    dictionary RTCInboundRTPStreamStats : RTCReceivedRTPStreamStats {
-      DOMString           remoteId;
-      unsigned long       framesDecoded;
-      DOMHighResTimeStamp lastPacketReceivedTimestamp;
+  7.4.  RTCInboundRtpStreamStats dictionary
+    dictionary RTCInboundRtpStreamStats : RTCReceivedRtpStreamStats {
+      DOMString            trackId;
+      DOMString            receiverId;
+      DOMString            remoteId;
+      unsigned long        framesDecoded;
+      unsigned long        keyFramesDecoded;
+      unsigned long        frameWidth;
+      unsigned long        frameHeight;
+      unsigned long        frameBitDepth;
+      double               framesPerSecond;
+      unsigned long long   qpSum;
+      double               totalDecodeTime;
+      double               totalInterFrameDelay;
+      double               totalSquaredInterFrameDelay;
+      boolean              voiceActivityFlag;
+      DOMHighResTimeStamp  lastPacketReceivedTimestamp;
+      double               averageRtcpInterval;
+      unsigned long long   headerBytesReceived;
+      unsigned long long   fecPacketsReceived;
+      unsigned long long   fecPacketsDiscarded;
+      unsigned long long   bytesReceived;
+      unsigned long long   packetsFailedDecryption;
+      unsigned long long   packetsDuplicated;
+      record<USVString, unsigned long long> perDscpPacketsReceived;
+      unsigned long        nackCount;
+      unsigned long        firCount;
+      unsigned long        pliCount;
+      unsigned long        sliCount;
+      DOMHighResTimeStamp  estimatedPlayoutTimestamp;
+      double        jitterBufferDelay;
+      unsigned long long   jitterBufferEmittedCount;
+      unsigned long long   totalSamplesReceived;
+      unsigned long long   samplesDecodedWithSilk;
+      unsigned long long   samplesDecodedWithCelt;
+      unsigned long long   concealedSamples;
+      unsigned long long   silentConcealedSamples;
+      unsigned long long   concealmentEvents;
+      unsigned long long   insertedSamplesForDeceleration;
+      unsigned long long   removedSamplesForAcceleration;
+      double               audioLevel;
+      double               totalAudioEnergy;
+      double               totalSamplesDuration;
+      unsigned long        framesReceived;
+      DOMString            decoderImplementation;
     };
 
   [webrtc-pc]
   8.6.  Mandatory To Implement Stats
-    - RTCInboundRTPStreamStats, with all required attributes from its inherited
-      dictionaries, and also attributes remoteId, framesDecoded
+    - RTCInboundRtpStreamStats, with all required attributes from its inherited
+      dictionaries, and also attributes receiverId, remoteId, framesDecoded, nackCount, framesReceived, bytesReceived, totalAudioEnergy, totalSampleDuration
  */
 function validateInboundRtpStreamStats(statsReport, stats) {
   validateReceivedRtpStreamStats(statsReport, stats);
-
+  validateOptionalIdField(statsReport, stats, 'trackId', 'track');
+  validateIdField(statsReport, stats, 'receiverId', 'receiver');
   validateIdField(statsReport, stats, 'remoteId', 'remote-outbound-rtp');
   assert_unsigned_int_field(stats, 'framesDecoded');
+  assert_optional_unsigned_int_field(stats, 'keyFramesDecoded');
+  assert_optional_unsigned_int_field(stats, 'frameWidth');
+  assert_optional_unsigned_int_field(stats, 'frameHeight');
+  assert_optional_unsigned_int_field(stats, 'frameBitDepth');
+  assert_optional_number_field(stats, 'framesPerSecond');
+  assert_optional_unsigned_int_field(stats, 'qpSum');
+  assert_optional_number_field(stats, 'totalDecodeTime');
+  assert_optional_number_field(stats, 'totalInterFrameDelay');
+  assert_optional_number_field(stats, 'totalSquaredInterFrameDelay');
+
+  assert_optional_boolean_field(stats, 'voiceActivityFlag');
+
   assert_optional_number_field(stats, 'lastPacketReceivedTimeStamp');
+  assert_optional_number_field(stats, 'averageRtcpInterval');
+
+  assert_optional_unsigned_int_field(stats, 'fecPacketsReceived');
+  assert_optional_unsigned_int_field(stats, 'fecPacketsDiscarded');
+  assert_unsigned_int_field(stats, 'bytesReceived');
+  assert_optional_unsigned_int_field(stats, 'packetsFailedDecryption');
+  assert_optional_unsigned_int_field(stats, 'packetsDuplicated');
+
+  assert_optional_dict_field(stats, 'perDscpPacketsReceived');
+  if (stats['perDscpPacketsReceived']) {
+    Object.keys(stats['perDscpPacketsReceived'])
+      .forEach(k =>
+               assert_equals(typeof k, 'string', 'Expect keys of perDscpPacketsReceived to be strings')
+              );
+    Object.values(stats['perDscpPacketsReceived'])
+      .forEach(v =>
+               assert_true(Number.isInteger(v) && (v >= 0), 'Expect values of perDscpPacketsReceived to be strings')
+              );
+  }
+
+  assert_unsigned_int_field(stats, 'nackCount');
+
+  assert_optional_unsigned_int_field(stats, 'firCount');
+  assert_optional_unsigned_int_field(stats, 'pliCount');
+  assert_optional_unsigned_int_field(stats, 'sliCount');
+
+  assert_optional_number_field(stats, 'estimatedPlayoutTimestamp');
+  assert_optional_number_field(stats, 'jitterBufferDelay');
+  assert_optional_unsigned_int_field(stats, 'jitterBufferEmittedCount');
+  assert_optional_unsigned_int_field(stats, 'totalSamplesReceived');
+  assert_optional_unsigned_int_field(stats, 'samplesDecodedWithSilk');
+  assert_optional_unsigned_int_field(stats, 'samplesDecodedWithCelt');
+  assert_optional_unsigned_int_field(stats, 'concealedSamples');
+  assert_optional_unsigned_int_field(stats, 'silentConcealedSamples');
+  assert_optional_unsigned_int_field(stats, 'concealmentEvents');
+  assert_optional_unsigned_int_field(stats, 'insertedSamplesForDeceleration');
+  assert_optional_unsigned_int_field(stats, 'removedSamplesForAcceleration');
+  assert_optional_number_field(stats, 'audioLevel');
+  assert_optional_number_field(stats, 'totalAudioEnergy');
+  assert_optional_number_field(stats, 'totalSamplesDuration');
+  assert_unsigned_int_field(stats, 'framesReceived');
+  assert_optional_string_field(stats, 'decoderImplementation');
 }
 
 /*
   [webrtc-stats]
-  7.5.  RTCRemoteInboundRTPStreamStats dictionary
-    dictionary RTCRemoteInboundRTPStreamStats : RTCReceivedRTPStreamStats {
-        DOMString localId;
-        double    roundTripTime;
+  7.5.  RTCRemoteInboundRtpStreamStats dictionary
+    dictionary RTCRemoteInboundRtpStreamStats : RTCReceivedRtpStreamStats {
+      DOMString            localId;
+      double               roundTripTime;
+      double               totalRoundTripTime;
+      double               fractionLost;
+      unsigned long long   reportsReceived;
+      unsigned long long   roundTripTimeMeasurements;
     };
 
   [webrtc-pc]
   8.6.  Mandatory To Implement Stats
-    - RTCRemoteInboundRTPStreamStats, with all required attributes from its
+    - RTCRemoteInboundRtpStreamStats, with all required attributes from its
       inherited dictionaries, and also attributes localId, roundTripTime
  */
 function validateRemoteInboundRtpStreamStats(statsReport, stats) {
@@ -315,74 +405,171 @@
 
   validateIdField(statsReport, stats, 'localId', 'outbound-rtp');
   assert_number_field(stats, 'roundTripTime');
+  assert_optional_number_field(stats, 'totalRoundTripTime');
+  assert_optional_number_field(stats, 'fractionLost');
+  assert_optional_unsigned_int_field(stats, 'reportsReceived');
+  assert_optional_unsigned_int_field(stats, 'roundTripTimeMeasurements');
 }
 
 /*
   [webrtc-stats]
-  7.6.  RTCSentRTPStreamStats dictionary
-    dictionary RTCSentRTPStreamStats : RTCRTPStreamStats {
+  7.6.  RTCSentRtpStreamStats dictionary
+    dictionary RTCSentRtpStreamStats : RTCRtpStreamStats {
       unsigned long      packetsSent;
-      unsigned long      packetsDiscardedOnSend;
       unsigned long long bytesSent;
-      unsigned long long bytesDiscardedOnSend;
     };
 
     [webrtc-pc]
     8.6.  Mandatory To Implement Stats
-      - RTCSentRTPStreamStats, with all required attributes from its inherited
+      - RTCSentRtpStreamStats, with all required attributes from its inherited
         dictionaries, and also attributes packetsSent, bytesSent
  */
 function validateSentRtpStreamStats(statsReport, stats) {
   validateRtpStreamStats(statsReport, stats);
 
   assert_unsigned_int_field(stats, 'packetsSent');
-  assert_optional_unsigned_int_field(stats, 'packetsDiscardedOnSend');
   assert_unsigned_int_field(stats, 'bytesSent');
-  assert_optional_unsigned_int_field(stats, 'bytesDiscardedOnSend');
 }
 
 /*
   [webrtc-stats]
-  7.7.  RTCOutboundRTPStreamStats dictionary
-    dictionary RTCOutboundRTPStreamStats : RTCSentRTPStreamStats {
-      DOMString           remoteId;
-      DOMHighResTimeStamp lastPacketSentTimestamp;
-      double              targetBitrate;
-      unsigned long       framesEncoded;
-      double              totalEncodeTime;
-      double              averageRTCPInterval;
+  7.7.  RTCOutboundRtpStreamStats dictionary
+    dictionary RTCOutboundRtpStreamStats : RTCSentRtpStreamStats {
+      DOMString            trackId;
+      DOMString            mediaSourceId;
+      DOMString            senderId;
+      DOMString            remoteId;
+      DOMString            rid;
+      DOMHighResTimeStamp  lastPacketSentTimestamp;
+      unsigned long long   headerBytesSent;
+      unsigned long        packetsDiscardedOnSend;
+      unsigned long long   bytesDiscardedOnSend;
+      unsigned long        fecPacketsSent;
+      unsigned long long   retransmittedPacketsSent;
+      unsigned long long   retransmittedBytesSent;
+      double               targetBitrate;
+      unsigned long long   totalEncodedBytesTarget;
+      unsigned long        frameWidth;
+      unsigned long        frameHeight;
+      unsigned long        frameBitDepth;
+      double               framesPerSecond;
+      unsigned long        framesSent;
+      unsigned long        hugeFramesSent;
+      unsigned long        framesEncoded;
+      unsigned long        keyFramesEncoded;
+      unsigned long        framesDiscardedOnSend;
+      unsigned long long   qpSum;
+      unsigned long long   totalSamplesSent;
+      unsigned long long   samplesEncodedWithSilk;
+      unsigned long long   samplesEncodedWithCelt;
+      boolean              voiceActivityFlag;
+      double               totalEncodeTime;
+      double               totalPacketSendDelay;
+      double               averageRtcpInterval;
+      RTCQualityLimitationReason          qualityLimitationReason;
+      record<DOMString, double> qualityLimitationDurations;
+      unsigned long        qualityLimitationResolutionChanges;
+      record<USVString, unsigned long long> perDscpPacketsSent;
+      unsigned long        nackCount;
+      unsigned long        firCount;
+      unsigned long        pliCount;
+      unsigned long        sliCount;
+      DOMString            encoderImplementation;
     };
 
     [webrtc-pc]
     8.6.  Mandatory To Implement Stats
-      - RTCOutboundRTPStreamStats, with all required attributes from its
-        inherited dictionaries, and also attributes remoteId, framesEncoded
+      - RTCOutboundRtpStreamStats, with all required attributes from its
+        inherited dictionaries, and also attributes senderId, remoteId, framesEncoded, nackCount, framesSent
  */
 function validateOutboundRtpStreamStats(statsReport, stats) {
   validateSentRtpStreamStats(statsReport, stats)
 
+  validateOptionalIdField(statsReport, stats, 'trackId', 'track');
+  validateOptionalIdField(statsReport, stats, 'mediaSourceId', 'media-source');
+  validateIdField(statsReport, stats, 'senderId', 'sender');
   validateIdField(statsReport, stats, 'remoteId', 'remote-inbound-rtp');
 
+  assert_optional_string_field(stats, 'rid');
+
   assert_optional_number_field(stats, 'lastPacketSentTimestamp');
+  assert_optional_unsigned_int_field(stats, 'headerBytesSent');
+  assert_optional_unsigned_int_field(stats, 'packetsDiscardedOnSend');
+  assert_optional_unsigned_int_field(stats, 'bytesDiscardedOnSend');
+  assert_optional_unsigned_int_field(stats, 'fecPacketsSent');
+  assert_optional_unsigned_int_field(stats, 'retransmittedPacketsSent');
+  assert_optional_unsigned_int_field(stats, 'retransmittedBytesSent');
   assert_optional_number_field(stats, 'targetBitrate');
-  if (stats['mediaType'] == 'video') {
+  assert_optional_unsigned_int_field(stats, 'totalEncodedBytesTarget');
+  if (stats['kind'] === 'video') {
+    assert_optional_unsigned_int_field(stats, 'frameWidth');
+    assert_optional_unsigned_int_field(stats, 'frameHeight');
+    assert_optional_unsigned_int_field(stats, 'frameBitDepth');
+    assert_optional_number_field(stats, 'framesPerSecond');
+    assert_unsigned_int_field(stats, 'framesSent');
+    assert_optional_unsigned_int_field(stats, 'hugeFramesSent');
     assert_unsigned_int_field(stats, 'framesEncoded');
+    assert_optional_unsigned_int_field(stats, 'keyFramesEncoded');
+    assert_optional_unsigned_int_field(stats, 'framesDiscardedOnSend');
+    assert_optional_unsigned_int_field(stats, 'qpSum');
+  } else   if (stats['kind'] === 'audio') {
+    assert_optional_unsigned_int_field(stats, 'totalSamplesSent');
+    assert_optional_unsigned_int_field(stats, 'samplesEncodedWithSilk');
+    assert_optional_unsigned_int_field(stats, 'samplesEncodedWithCelt');
+    assert_optional_boolean_field(stats, 'voiceActivityFlag');
   }
   assert_optional_number_field(stats, 'totalEncodeTime');
+  assert_optional_number_field(stats, 'totalPacketSendDelay');
   assert_optional_number_field(stats, 'averageRTCPInterval');
+
+  if (stats['kind'] === 'video') {
+    assert_optional_enum_field(stats, 'qualityLimitationReason', ['none', 'cpu', 'bandwidth', 'other']);
+
+    assert_optional_dict_field(stats, 'qualityLimitationDurations');
+    if (stats['qualityLimitationDurations']) {
+      Object.keys(stats['qualityLimitationDurations'])
+        .forEach(k =>
+                 assert_equals(typeof k, 'string', 'Expect keys of qualityLimitationDurations to be strings')
+                );
+      Object.values(stats['qualityLimitationDurations'])
+        .forEach(v =>
+                 assert_equals(typeof num, 'number', 'Expect values of qualityLimitationDurations to be numbers')
+                );
+    }
+
+    assert_optional_unsigned_int_field(stats, 'qualityLimitationResolutionChanges');
+    }
+  assert_unsigned_int_field(stats, 'nackCount');
+  assert_optional_dict_field(stats, 'perDscpPacketsSent');
+  if (stats['perDscpPacketsSent']) {
+    Object.keys(stats['perDscpPacketsSent'])
+      .forEach(k =>
+               assert_equals(typeof k, 'string', 'Expect keys of perDscpPacketsSent to be strings')
+              );
+    Object.values(stats['perDscpPacketsSent'])
+      .forEach(v =>
+               assert_true(Number.isInteger(v) && (v >= 0), 'Expect values of perDscpPacketsSent to be strings')
+              );
+  }
+
+  assert_optional_unsigned_int_field(stats, 'firCount');
+  assert_optional_unsigned_int_field(stats, 'pliCount');
+  assert_optional_unsigned_int_field(stats, 'sliCount');
+  assert_optional_string_field(stats, 'encoderImplementation');
 }
 
 /*
   [webrtc-stats]
-  7.8.  RTCRemoteOutboundRTPStreamStats dictionary
-    dictionary RTCRemoteOutboundRTPStreamStats : RTCSentRTPStreamStats {
+  7.8.  RTCRemoteOutboundRtpStreamStats dictionary
+    dictionary RTCRemoteOutboundRtpStreamStats : RTCSentRtpStreamStats {
       DOMString           localId;
       DOMHighResTimeStamp remoteTimestamp;
+      unsigned long long  reportsSent;
     };
 
   [webrtc-pc]
   8.6.  Mandatory To Implement Stats
-    - RTCRemoteOutboundRTPStreamStats, with all required attributes from its
+    - RTCRemoteOutboundRtpStreamStats, with all required attributes from its
       inherited dictionaries, and also attributes localId, remoteTimestamp
  */
 function validateRemoteOutboundRtpStreamStats(statsReport, stats) {
@@ -390,6 +577,58 @@
 
   validateIdField(statsReport, stats, 'localId', 'inbound-rtp');
   assert_number_field(stats, 'remoteTimeStamp');
+  assert_optional_unsigned_int_field(stats, 'reportsSent');
+}
+
+/*
+  [webrtc-stats]
+  7.11 RTCMediaSourceStats dictionary
+  dictionary RTCMediaSourceStats : RTCStats {
+      DOMString       trackIdentifier;
+      DOMString       kind;
+  };
+
+  dictionary RTCAudioSourceStats : RTCMediaSourceStats {
+       double       audioLevel;
+       double       totalAudioEnergy;
+       double       totalSamplesDuration;
+       double       echoReturnLoss;
+       double       echoReturnLossEnhancement;
+  };
+
+  dictionary RTCVideoSourceStats : RTCMediaSourceStats {
+      unsigned long   width;
+      unsigned long   height;
+      unsigned long   bitDepth;
+      unsigned long   frames;
+      // see https://github.com/w3c/webrtc-stats/issues/540
+      double   framesPerSecond;
+  };
+
+  [webrtc-pc]
+  8.6.  Mandatory To Implement Stats
+  RTCMediaSourceStats with attributes trackIdentifier, kind
+  RTCAudioSourceStats, with all required attributes from its inherited dictionaries and totalAudioEnergy, totalSamplesDuration
+  RTCVideoSourceStats, with all required attributes from its inherited dictionaries and width, height, framesPerSecond
+*/
+function validateMediaSourceStats(statsReport, stats) {
+  validateRtcStats(statsReport, stats);
+  assert_string_field(stats, 'trackIdentifier');
+  assert_enum_field(stats, 'kind', ['audio', 'video']);
+
+  if (stats.kind === 'audio') {
+    assert_optional_number_field(stats, 'audioLevel');
+    assert_number_field(stats, 'totalAudioEnergy');
+    assert_number_field(stats, 'totalSamplesDuration');
+    assert_optional_number_field(stats, 'echoReturnLoss');
+    assert_optional_number_field(stats, 'echoReturnLossEnhancement');
+  } else if (stats.kind === 'video') {
+    assert_unsigned_int_field(stats, 'width');
+    assert_unsigned_int_field(stats, 'height');
+    assert_optional_unsigned_int_field(stats, 'bitDpeth');
+    assert_optional_unsigned_int_field(stats, 'frames');
+    assert_number_field(stats, 'framesPerSecond');
+  }
 }
 
 /*
@@ -435,145 +674,102 @@
   assert_optional_unsigned_int_field(stats, 'dataChannelsAccepted');
 }
 
-/*
-  [webrtc-stats]
-  7.11. RTCMediaStreamStats dictionary
-    dictionary RTCMediaStreamStats : RTCStats {
-      DOMString           streamIdentifier;
-      sequence<DOMString> trackIds;
-    };
-
-  [webrtc-pc]
-  8.6.  Mandatory To Implement Stats
-    - RTCMediaStreamStats, with attributes streamIdentifer, trackIds
- */
-function validateMediaStreamStats(statsReport, stats) {
+/* [webrtc-stats]
+  7.16 RTCRtpTransceiverStats dictionary
+  dictionary RTCRtpTransceiverStats {
+    DOMString senderId;
+    DOMString receiverId;
+    DOMString mid;
+  };
+*/
+function validateTransceiverStats(statsReport, stats) {
   validateRtcStats(statsReport, stats);
-
-  assert_string_field(stats, 'streamIdentifier');
-  assert_array_field(stats, 'trackIds');
-
-  for(const trackId of stats.trackIds) {
-    assert_equals(typeof trackId, 'string',
-      'Expect trackId elements to be string');
-
-    assert_true(statsReport.has(trackId),
-      `Expect stats report to have stats object with id ${trackId}`);
-
-    const trackStats = statsReport.get(trackId);
-    assert_equals(trackStats.type, 'track',
-      `Expect track stats object to have type 'track'`);
-  }
+  validateOptionalIdField(statsReport, stats, 'senderId', 'sender');
+  validateOptionalIdField(statsReport, stats, 'receiverId', 'sender');
+  assert_optional_string_field(stats, 'mid');
 }
 
 /*
   [webrtc-stats]
-  7.12. RTCMediaStreamTrackStats dictionary
-    dictionary RTCMediaStreamTrackStats : RTCStats {
+  dictionary RTCMediaHandlerStats : RTCStats {
       DOMString           trackIdentifier;
-      boolean             remoteSource;
-      boolean             ended;
-      boolean             detached;
+      boolean      remoteSource;
+      boolean      ended;
       DOMString           kind;
-      DOMHighResTimeStamp estimatedPlayoutTimestamp;
-      unsigned long       frameWidth;
-      unsigned long       frameHeight;
-      double              framesPerSecond;
-      unsigned long       framesCaptured;
-      unsigned long       framesSent;
-      unsigned long       keyFramesSent;
-      unsigned long       framesReceived;
-      unsigned long       keyFramesReceived;
-      unsigned long       framesDecoded;
-      unsigned long       framesDropped;
-      unsigned long       framesCorrupted;
-      unsigned long       partialFramesLost;
-      unsigned long       fullFramesLost;
-      double              audioLevel;
-      double              totalAudioEnergy;
-      boolean             voiceActivityFlag;
-      double              echoReturnLoss;
-      double              echoReturnLossEnhancement;
-      unsigned long long  totalSamplesSent;
-      unsigned long long  totalSamplesReceived;
-      double              totalSamplesDuration;
-      unsigned long long  concealedSamples;
-      unsigned long long  concealmentEvents;
-      double              jitterBufferDelay;
       RTCPriorityType     priority;
-    };
+  };
+  dictionary RTCVideoHandlerStats : RTCMediaHandlerStats {
+  };
+  dictionary RTCAudioHandlerStats : RTCMediaHandlerStats {
+  };
+  Used from validateSenderStats and validateReceiverStats
+
+  [webrtc-priority]
+  enum RTCPriorityType {
+    "very-low",
+    "low",
+    "medium",
+    "high"
+  };
 
   [webrtc-pc]
-  4.9.1.  RTCPriorityType Enum
-    enum RTCPriorityType {
-      "very-low",
-      "low",
-      "medium",
-      "high"
-    };
+  MTI:
+  RTCMediaHandlerStats with attributes trackIdentifier
+  RTCAudioHandlerStats, with all required attributes from its inherited dictionaries
+  RTCVideoHandlerStats, with all required attributes from its inherited dictionaries
 
-  8.6.  Mandatory To Implement Stats
-    - RTCMediaStreamTrackStats, with attributes trackIdentifier, remoteSource,
-      ended, detached, frameWidth, frameHeight, framesPerSecond, framesSent,
-      framesReceived, framesDecoded, framesDropped, framesCorrupted, audioLevel
- */
-
-function validateMediaStreamTrackStats(statsReport, stats) {
+*/
+function validateMediaHandlerStats(statsReport, stats) {
   validateRtcStats(statsReport, stats);
-
   assert_string_field(stats, 'trackIdentifier');
-  assert_boolean_field(stats, 'remoteSource');
-  assert_boolean_field(stats, 'ended');
-  assert_boolean_field(stats, 'detached');
-
-  assert_optional_enum_field(stats, 'kind', ['audio', 'video']);
-  assert_optional_number_field(stats, 'estimatedPlayoutTimestamp');
-  if (stats['kind'] === 'video') {
-    assert_unsigned_int_field(stats, 'frameWidth');
-    assert_unsigned_int_field(stats, 'frameHeight');
-    assert_number_field(stats, 'framesPerSecond');
-    if (stats['framesSent']) {
-      assert_optional_unsigned_int_field(stats, 'framesCaptured');
-      assert_unsigned_int_field(stats, 'framesSent');
-      assert_optional_unsigned_int_field(stats, 'keyFramesSent');
-    } else {
-      assert_unsigned_int_field(stats, 'framesReceived');
-      assert_optional_unsigned_int_field(stats, 'keyFramesReceived');
-      assert_unsigned_int_field(stats, 'framesDecoded');
-      assert_unsigned_int_field(stats, 'framesDropped');
-      assert_unsigned_int_field(stats, 'framesCorrupted');
-    }
-
-    assert_optional_unsigned_int_field(stats, 'partialFramesLost');
-    assert_optional_unsigned_int_field(stats, 'fullFramesLost');
-  } else {
-    if (stats['remoteSource']) {
-      assert_number_field(stats, 'audioLevel');
-      assert_optional_number_field(stats, 'totalAudioEnergy');
-      assert_optional_number_field(stats, 'totalSamplesDuration');
-    }
-    assert_optional_boolean_field(stats, 'voiceActivityFlag');
-    assert_optional_number_field(stats, 'echoReturnLoss');
-    assert_optional_number_field(stats, 'echoReturnLossEnhancement');
-
-    assert_optional_unsigned_int_field(stats, 'totalSamplesSent');
-    assert_optional_unsigned_int_field(stats, 'totalSamplesReceived');
-    assert_optional_unsigned_int_field(stats, 'concealedSamples');
-    assert_optional_unsigned_int_field(stats, 'concealmentEvents');
-    assert_optional_number_field(stats, 'jitterBufferDelay');
-  }
-
-  assert_optional_enum_field(stats, 'priority',
-    ['very-low', 'low', 'medium', 'high']);
+  assert_optional_boolean_field(stats, 'remoteSource');
+  assert_optional_boolean_field(stats, 'ended');
+  assert_optional_string_field(stats, 'kind');
+  assert_enum_field(stats, 'priority', ['very-low', 'low', 'medium', 'high']);
 }
 
 /*
+ [webrtc-stats]
+  dictionary RTCAudioSenderStats : RTCAudioHandlerStats {
+      DOMString           mediaSourceId;
+  };
+  dictionary RTCVideoSenderStats : RTCVideoHandlerStats {
+      DOMString           mediaSourceId;
+  };
+
+  [webrtc-pc]
+  MTI:
+  RTCVideoSenderStats, with all required attributes from its inherited dictionaries
+*/
+function validateSenderStats(statsReport, stats) {
+  validateMediaHandlerStats(statsReport, stats);
+  validateOptionalIdField(statsReport, stats, 'mediaSourceId', 'media-source');
+}
+
+/*
+ [webrtc-stats]
+  dictionary RTCAudioReceiverStats : RTCAudioHandlerStats {
+  };
+  dictionary RTCVideoReceiverStats : RTCVideoHandlerStats {
+  };
+
+  [webrtc-pc]
+  MTI:
+  RTCVideoReceiverStats, with all required attributes from its inherited dictionaries
+*/
+function validateReceiverStats(statsReport, stats) {
+  validateMediaHandlerStats(statsReport, stats);
+}
+
+
+/*
   [webrtc-stats]
   7.13. RTCDataChannelStats dictionary
     dictionary RTCDataChannelStats : RTCStats {
       DOMString           label;
       DOMString           protocol;
-      long                dataChannelIdentifier;
+      // see https://github.com/w3c/webrtc-stats/issues/541
+      unsigned short      dataChannelIdentifier;
       DOMString           transportId;
       RTCDataChannelState state;
       unsigned long       messagesSent;
@@ -592,7 +788,7 @@
     };
 
   8.6.  Mandatory To Implement Stats
-    - RTCDataChannelStats, with attributes label, protocol, datachannelId, state,
+    - RTCDataChannelStats, with attributes label, protocol, datachannelIdentifier, state,
       messagesSent, bytesSent, messagesReceived, bytesReceived
  */
 function validateDataChannelStats(statsReport, stats) {
@@ -600,7 +796,7 @@
 
   assert_string_field(stats, 'label');
   assert_string_field(stats, 'protocol');
-  assert_int_field(stats, 'dataChannelIdentifier');
+  assert_unsigned_int_field(stats, 'dataChannelIdentifier');
 
   validateOptionalIdField(statsReport, stats, 'transportId', 'transport');
 
@@ -617,8 +813,8 @@
   [webrtc-stats]
   7.14. RTCTransportStats dictionary
     dictionary RTCTransportStats : RTCStats {
-      unsigned long         packetsSent;
-      unsigned long         packetsReceived;
+      unsigned long long    packetsSent;
+      unsigned long long    packetsReceived;
       unsigned long long    bytesSent;
       unsigned long long    bytesReceived;
       DOMString             rtcpTransportStatsId;
@@ -627,6 +823,11 @@
       DOMString             selectedCandidatePairId;
       DOMString             localCertificateId;
       DOMString             remoteCertificateId;
+      DOMString             tlsVersion;
+      DOMString             dtlsCipher;
+      DOMString             srtpCipher;
+      DOMString             tlsGroup;
+      unsigned long         selectedCandidatePairChanges;
     };
 
   [webrtc-pc]
@@ -641,13 +842,14 @@
 
   5.6.  RTCIceRole Enum
     enum RTCIceRole {
+      "unknown",
       "controlling",
       "controlled"
     };
 
   8.6.  Mandatory To Implement Stats
     - RTCTransportStats, with attributes bytesSent, bytesReceived,
-      rtcpTransportStatsId, selectedCandidatePairId, localCertificateId,
+      selectedCandidatePairId, localCertificateId,
       remoteCertificateId
  */
 function validateTransportStats(statsReport, stats) {
@@ -662,7 +864,7 @@
                           'transport');
 
   assert_optional_enum_field(stats, 'iceRole',
-    ['controlling', 'controlled']);
+                             ['unknown', 'controlling', 'controlled']);
 
   assert_optional_enum_field(stats, 'dtlsState',
     ['new', 'connecting', 'connected', 'closed', 'failed']);
@@ -670,6 +872,11 @@
   validateIdField(statsReport, stats, 'selectedCandidatePairId', 'candidate-pair');
   validateIdField(statsReport, stats, 'localCertificateId', 'certificate');
   validateIdField(statsReport, stats, 'remoteCertificateId', 'certificate');
+  assert_optional_string_field(stats, 'tlsVersion');
+  assert_optional_string_field(stats, 'dtlsCipher');
+  assert_optional_string_field(stats, 'srtpCipher');
+  assert_optional_string_field(stats, 'tlsGroup');
+  assert_optional_unsigned_int_field(stats, 'selectedCandidatePairChanges');
 }
 
 /*
@@ -677,26 +884,13 @@
   7.15. RTCIceCandidateStats dictionary
     dictionary RTCIceCandidateStats : RTCStats {
       DOMString           transportId;
-      boolean             isRemote;
-      RTCNetworkType      networkType;
-      DOMString           ip;
+      DOMString           address;
       long                port;
       DOMString           protocol;
       RTCIceCandidateType candidateType;
       long                priority;
       DOMString           url;
       DOMString           relayProtocol;
-      boolean             deleted = false;
-    };
-
-    enum RTCNetworkType {
-      "bluetooth",
-      "cellular",
-      "ethernet",
-      "wifi",
-      "wimax",
-      "vpn",
-      "unknown"
     };
 
   [webrtc-pc]
@@ -709,29 +903,23 @@
     };
 
   8.6.  Mandatory To Implement Stats
-    - RTCIceCandidateStats, with attributes ip, port, protocol, candidateType,
-      priority, url
+    - RTCIceCandidateStats, with attributes address, port, protocol, candidateType, url
  */
 function validateIceCandidateStats(statsReport, stats) {
   validateRtcStats(statsReport, stats);
 
   validateOptionalIdField(statsReport, stats, 'transportId', 'transport');
-  assert_optional_boolean_field(stats, 'isRemote');
 
-  assert_optional_enum_field(stats, 'networkType',
-    ['bluetooth', 'cellular', 'ethernet', 'wifi', 'wimax', 'vpn', 'unknown'])
-
-  assert_string_field(stats, 'ip');
-  assert_int_field(stats, 'port');
+  assert_string_field(stats, 'address');
+  assert_unsigned_int_field(stats, 'port');
   assert_string_field(stats, 'protocol');
 
   assert_enum_field(stats, 'candidateType',
     ['host', 'srflx', 'prflx', 'relay']);
 
-  assert_int_field(stats, 'priority');
-  assert_optional_string_field(stats, 'url');
+  assert_optional_int_field(stats, 'priority');
+  assert_string_field(stats, 'url');
   assert_optional_string_field(stats, 'relayProtocol');
-  assert_optional_boolean_field(stats, 'deleted');
 }
 
 /*
@@ -742,7 +930,6 @@
       DOMString                     localCandidateId;
       DOMString                     remoteCandidateId;
       RTCStatsIceCandidatePairState state;
-      unsigned long long            priority;
       boolean                       nominated;
       unsigned long                 packetsSent;
       unsigned long                 packetsReceived;
@@ -766,7 +953,8 @@
       unsigned long long            retransmissionsSent;
       unsigned long long            consentRequestsSent;
       DOMHighResTimeStamp           consentExpiredTimestamp;
-    };
+      unsigned long                 packetsDiscardedOnSend;
+      unsigned long long            bytesDiscardedOnSend;    };
 
     enum RTCStatsIceCandidatePairState {
       "frozen",
@@ -779,7 +967,8 @@
   [webrtc-pc]
   8.6.  Mandatory To Implement Stats
     - RTCIceCandidatePairStats, with attributes transportId, localCandidateId,
-      remoteCandidateId, state, priority, nominated, bytesSent, bytesReceived, totalRoundTripTime, currentRoundTripTime
+      remoteCandidateId, state, nominated, bytesSent, bytesReceived, totalRoundTripTime, currentRoundTripTime
+   // not including priority per https://github.com/w3c/webrtc-pc/issues/2457
  */
 function validateIceCandidatePairStats(statsReport, stats) {
   validateRtcStats(statsReport, stats);
@@ -791,7 +980,6 @@
   assert_enum_field(stats, 'state',
     ['frozen', 'waiting', 'in-progress', 'failed', 'succeeded']);
 
-  assert_unsigned_int_field(stats, 'priority');
   assert_boolean_field(stats, 'nominated');
   assert_optional_unsigned_int_field(stats, 'packetsSent');
   assert_optional_unsigned_int_field(stats, 'packetsReceived');
@@ -819,6 +1007,8 @@
   assert_optional_unsigned_int_field(stats, 'retransmissionsSent');
   assert_optional_unsigned_int_field(stats, 'consentRequestsSent');
   assert_optional_number_field(stats, 'consentExpiredTimestamp');
+  assert_optional_unsigned_int_field(stats, 'packetsDiscardedOnSend');
+  assert_optional_unsigned_int_field(stats, 'bytesDiscardedOnSend');
 }
 
 /*
@@ -844,3 +1034,26 @@
   assert_string_field(stats, 'base64Certificate');
   assert_optional_string_field(stats, 'issuerCertificateId');
 }
+
+/*
+  [webrtc-stats]
+  7.30. RTCIceServerStats dictionary
+  dictionary RTCIceServerStats : RTCStats {
+      DOMString url;
+      long port;
+      DOMString protocol;
+      unsigned long totalRequestsSent;
+      unsigned long totalResponsesReceived;
+      double totalRoundTripTime;
+    };
+*/
+function validateIceServerStats(statsReport, stats) {
+  validateRtcStats(statsReport, stats);
+
+  assert_optional_string_field(stats, 'url');
+  assert_optional_int_field(stats, 'port');
+  assert_optional_string_field(stats, 'protocol');
+  assert_optional_unsigned_int_field(stats, 'totalRequestsSent');
+  assert_optional_unsigned_int_field(stats, 'totalResponsesReceived');
+  assert_optional_number_field(stats, 'totalRoundTripTime');
+}
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/legacy/RTCPeerConnection-addStream.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/legacy/RTCPeerConnection-addStream.https-expected.txt
new file mode 100644
index 0000000..e2df6c1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc/legacy/RTCPeerConnection-addStream.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught SyntaxError: Unexpected string
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/protocol/crypto-suite.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/protocol/crypto-suite.https-expected.txt
index 1d818ac..e2df6c1 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/protocol/crypto-suite.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/protocol/crypto-suite.https-expected.txt
@@ -1,11 +1,4 @@
 This is a testharness.js-based test.
-PASS tlsVersion is acceptable on data-only
-PASS tlsVersion is acceptable on video-only
-PASS dtlsCipher is acceptable on data-only
-PASS dtlsCipher is acceptable on video-only
-PASS srtpCipher is acceptable on data-only
-PASS srtpCipher is acceptable on video-only
-FAIL tlsGroup is acceptable on data-only assert_true: Value present: expected true got false
-FAIL tlsGroup is acceptable on video-only assert_true: Value present: expected true got false
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught SyntaxError: Unexpected string
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/xhr/idlharness.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/xhr/idlharness.any.sharedworker-expected.txt
index d6f6505..70da516 100644
--- a/third_party/blink/web_tests/external/wpt/xhr/idlharness.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/xhr/idlharness.any.sharedworker-expected.txt
@@ -61,7 +61,7 @@
 PASS XMLHttpRequest interface: attribute timeout
 PASS XMLHttpRequest interface: attribute withCredentials
 PASS XMLHttpRequest interface: attribute upload
-PASS XMLHttpRequest interface: operation send(optional (Document or BodyInit)?)
+PASS XMLHttpRequest interface: operation send(optional (Document or XMLHttpRequestBodyInit)?)
 PASS XMLHttpRequest interface: operation abort()
 PASS XMLHttpRequest interface: attribute responseURL
 PASS XMLHttpRequest interface: attribute status
@@ -91,8 +91,8 @@
 PASS XMLHttpRequest interface: new XMLHttpRequest() must inherit property "timeout" with the proper type
 PASS XMLHttpRequest interface: new XMLHttpRequest() must inherit property "withCredentials" with the proper type
 PASS XMLHttpRequest interface: new XMLHttpRequest() must inherit property "upload" with the proper type
-PASS XMLHttpRequest interface: new XMLHttpRequest() must inherit property "send(optional (Document or BodyInit)?)" with the proper type
-PASS XMLHttpRequest interface: calling send(optional (Document or BodyInit)?) on new XMLHttpRequest() with too few arguments must throw TypeError
+PASS XMLHttpRequest interface: new XMLHttpRequest() must inherit property "send(optional (Document or XMLHttpRequestBodyInit)?)" with the proper type
+PASS XMLHttpRequest interface: calling send(optional (Document or XMLHttpRequestBodyInit)?) on new XMLHttpRequest() with too few arguments must throw TypeError
 PASS XMLHttpRequest interface: new XMLHttpRequest() must inherit property "abort()" with the proper type
 PASS XMLHttpRequest interface: new XMLHttpRequest() must inherit property "responseURL" with the proper type
 PASS XMLHttpRequest interface: new XMLHttpRequest() must inherit property "status" with the proper type
diff --git a/third_party/blink/web_tests/external/wpt/xhr/idlharness.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/xhr/idlharness.any.worker-expected.txt
index d6f6505..70da516 100644
--- a/third_party/blink/web_tests/external/wpt/xhr/idlharness.any.worker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/xhr/idlharness.any.worker-expected.txt
@@ -61,7 +61,7 @@
 PASS XMLHttpRequest interface: attribute timeout
 PASS XMLHttpRequest interface: attribute withCredentials
 PASS XMLHttpRequest interface: attribute upload
-PASS XMLHttpRequest interface: operation send(optional (Document or BodyInit)?)
+PASS XMLHttpRequest interface: operation send(optional (Document or XMLHttpRequestBodyInit)?)
 PASS XMLHttpRequest interface: operation abort()
 PASS XMLHttpRequest interface: attribute responseURL
 PASS XMLHttpRequest interface: attribute status
@@ -91,8 +91,8 @@
 PASS XMLHttpRequest interface: new XMLHttpRequest() must inherit property "timeout" with the proper type
 PASS XMLHttpRequest interface: new XMLHttpRequest() must inherit property "withCredentials" with the proper type
 PASS XMLHttpRequest interface: new XMLHttpRequest() must inherit property "upload" with the proper type
-PASS XMLHttpRequest interface: new XMLHttpRequest() must inherit property "send(optional (Document or BodyInit)?)" with the proper type
-PASS XMLHttpRequest interface: calling send(optional (Document or BodyInit)?) on new XMLHttpRequest() with too few arguments must throw TypeError
+PASS XMLHttpRequest interface: new XMLHttpRequest() must inherit property "send(optional (Document or XMLHttpRequestBodyInit)?)" with the proper type
+PASS XMLHttpRequest interface: calling send(optional (Document or XMLHttpRequestBodyInit)?) on new XMLHttpRequest() with too few arguments must throw TypeError
 PASS XMLHttpRequest interface: new XMLHttpRequest() must inherit property "abort()" with the proper type
 PASS XMLHttpRequest interface: new XMLHttpRequest() must inherit property "responseURL" with the proper type
 PASS XMLHttpRequest interface: new XMLHttpRequest() must inherit property "status" with the proper type
diff --git a/third_party/blink/web_tests/fast/backgrounds/size/backgroundSize10-expected.png b/third_party/blink/web_tests/fast/backgrounds/size/backgroundSize10-expected.png
index c6e2ad2..18c7735 100644
--- a/third_party/blink/web_tests/fast/backgrounds/size/backgroundSize10-expected.png
+++ b/third_party/blink/web_tests/fast/backgrounds/size/backgroundSize10-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/backgrounds/size/backgroundSize11-expected.png b/third_party/blink/web_tests/fast/backgrounds/size/backgroundSize11-expected.png
index 662c78fd..ef16225 100644
--- a/third_party/blink/web_tests/fast/backgrounds/size/backgroundSize11-expected.png
+++ b/third_party/blink/web_tests/fast/backgrounds/size/backgroundSize11-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/dom/shadow/input-color-in-content-expected.txt b/third_party/blink/web_tests/fast/dom/shadow/input-color-in-content-expected.txt
deleted file mode 100644
index 5e65c28..0000000
--- a/third_party/blink/web_tests/fast/dom/shadow/input-color-in-content-expected.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-CONSOLE WARNING: line 13: Element.createShadowRoot is deprecated and will be removed in M80, around February 2020. Please use Element.attachShadow instead. See https://www.chromestatus.com/features/4507242028072960 and https://developers.google.com/web/updates/2019/07/web-components-time-to-upgrade for more details.
-PASS mockColorChooser.isChooserShown() is false
-PASS mockColorChooser.isChooserShown() is true
-PASS mockColorChooser.isChooserShown() is true
-PASS mockColorChooser.isChooserShown() is true
-PASS mockColorChooser.isChooserShown() is true
-PASS mockColorChooser.isChooserShown() is true
-PASS mockColorChooser.isChooserShown() is true
-PASS mockColorChooser.isChooserShown() is true
-PASS mockColorChooser.isChooserShown() is true
-PASS mockColorChooser.isChooserShown() is true
-PASS mockColorChooser.isChooserShown() is true
-PASS mockColorChooser.isChooserShown() is true
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/become-composited-nested-iframes-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/become-composited-nested-iframes-expected.txt
index b608fa4..cf8c8cb 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/become-composited-nested-iframes-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/become-composited-nested-iframes-expected.txt
@@ -7,62 +7,42 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [284, 204],
+      "name": "LayoutView #document",
+      "bounds": [280, 200],
       "transform": 1
     },
     {
       "name": "LayoutView #document",
-      "bounds": [280, 200],
+      "bounds": [250, 170],
+      "contentsOpaqueForText": true,
+      "backgroundColor": "#C0C0C0",
       "transform": 2
     },
     {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [252, 172],
+      "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
+      "bounds": [210, 210],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
       "transform": 3
     },
     {
       "name": "LayoutView #document",
-      "bounds": [250, 170],
-      "contentsOpaqueForText": true,
-      "backgroundColor": "#C0C0C0",
+      "bounds": [280, 200],
       "transform": 4
     },
     {
-      "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "bounds": [210, 210],
-      "contentsOpaque": true,
-      "backgroundColor": "#0000FF",
-      "transform": 5
-    },
-    {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [284, 204],
-      "transform": 6
-    },
-    {
-      "name": "LayoutView #document",
-      "bounds": [280, 200],
-      "transform": 7
-    },
-    {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [252, 172],
-      "transform": 8
-    },
-    {
       "name": "LayoutView #document",
       "bounds": [250, 170],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 9
+      "transform": 5
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 10
+      "transform": 6
     },
     {
       "name": "LayoutBlockFlow DIV id='box' class='composited'",
@@ -84,7 +64,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [20, 120, 0, 1]
+        [22, 122, 0, 1]
       ]
     },
     {
@@ -94,7 +74,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [2, 2, 0, 1]
+        [9, 9, 0, 1]
       ]
     },
     {
@@ -104,17 +84,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [8, 8, 0, 1]
+        [18, 10, 0, 1]
       ]
     },
     {
       "id": 4,
-      "parent": 3,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [1, 1, 0, 1]
+        [22, 346, 0, 1]
       ]
     },
     {
@@ -124,51 +103,12 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [18, 10, 0, 1]
+        [9, 9, 0, 1]
       ]
     },
     {
       "id": 6,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [20, 344, 0, 1]
-      ]
-    },
-    {
-      "id": 7,
-      "parent": 6,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [2, 2, 0, 1]
-      ]
-    },
-    {
-      "id": 8,
-      "parent": 7,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [8, 8, 0, 1]
-      ]
-    },
-    {
-      "id": 9,
-      "parent": 8,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [1, 1, 0, 1]
-      ]
-    },
-    {
-      "id": 10,
-      "parent": 9,
+      "parent": 5,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/become-overlapped-iframe-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/become-overlapped-iframe-expected.txt
index eaf56d8..9e2e778 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/become-overlapped-iframe-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/become-overlapped-iframe-expected.txt
@@ -7,29 +7,24 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame (floating) IFRAME id='iframe'",
-      "bounds": [350, 200],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [305, 230],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [305, 0],
       "bounds": [15, 170],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='overlay'",
@@ -45,7 +40,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [58, 58, 0, 1]
+        [73, 73, 0, 1]
       ]
     },
     {
@@ -55,16 +50,6 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
-      ]
-    },
-    {
-      "id": 3,
-      "parent": 2,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [18, 10, 0, 1]
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/connect-compositing-iframe-delayed-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/connect-compositing-iframe-delayed-expected.txt
index d387ba1..0e489fd 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/connect-compositing-iframe-delayed-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/connect-compositing-iframe-delayed-expected.txt
@@ -9,37 +9,31 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME id='iframe'",
-      "position": [-30, -30],
-      "bounds": [390, 240],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [285, 230],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [285, 0],
       "bounds": [15, 150],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV id='box' class='composited'",
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 4
+      "transform": 3
     }
   ],
   "transforms": [
@@ -49,7 +43,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [28, 128, 0, 1]
+        [43, 143, 0, 1]
       ]
     },
     {
@@ -59,21 +53,11 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
-      ]
-    },
-    {
-      "id": 3,
-      "parent": 2,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [18, 10, 0, 1]
       ]
     },
     {
-      "id": 4,
+      "id": 3,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/enter-compositing-iframe-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/enter-compositing-iframe-expected.txt
index 67fc6aa2..a66713d38 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/enter-compositing-iframe-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/enter-compositing-iframe-expected.txt
@@ -7,30 +7,24 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME id='parent-iframe'",
-      "position": [-30, -30],
-      "bounds": [390, 240],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [285, 230],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV id='test' class='composited box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [285, 0],
       "bounds": [15, 150],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='overlay'",
@@ -46,7 +40,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [28, 28, 0, 1]
+        [43, 43, 0, 1]
       ]
     },
     {
@@ -56,16 +50,6 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
-      ]
-    },
-    {
-      "id": 3,
-      "parent": 2,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [18, 10, 0, 1]
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/iframe-resize-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/iframe-resize-expected.txt
index 88bcd13..42d74be9 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/iframe-resize-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/iframe-resize-expected.txt
@@ -7,30 +7,24 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME id='parent-iframe' class='bigger'",
-      "position": [-30, -30],
-      "bounds": [490, 210],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [385, 230],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [385, 0],
       "bounds": [15, 120],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='overlay'",
@@ -46,7 +40,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [28, 28, 0, 1]
+        [43, 43, 0, 1]
       ]
     },
     {
@@ -56,16 +50,6 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
-      ]
-    },
-    {
-      "id": 3,
-      "parent": 2,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [18, 10, 0, 1]
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/iframe-size-from-zero-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/iframe-size-from-zero-expected.txt
index b617955..263d5a33 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/iframe-size-from-zero-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/iframe-size-from-zero-expected.txt
@@ -7,29 +7,24 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME id='iframe' class='expanded'",
-      "bounds": [330, 180],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [285, 230],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [285, 0],
       "bounds": [15, 150],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='overlay'",
@@ -45,7 +40,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [28, 28, 0, 1]
+        [43, 43, 0, 1]
       ]
     },
     {
@@ -55,16 +50,6 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
-      ]
-    },
-    {
-      "id": 3,
-      "parent": 2,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [18, 10, 0, 1]
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/invisible-nested-iframe-show-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/invisible-nested-iframe-show-expected.txt
index 0452294..119d87b 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/invisible-nested-iframe-show-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/invisible-nested-iframe-show-expected.txt
@@ -7,47 +7,36 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME",
-      "position": [-30, -30],
-      "bounds": [390, 240],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [285, 193],
-      "transform": 2
-    },
-    {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [252, 172],
-      "transform": 3
+      "transform": 1
     },
     {
       "name": "LayoutView #document",
       "bounds": [250, 170],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 4
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 5
+      "transform": 3
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [285, 0],
       "bounds": [15, 150],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 7
+      "transform": 5
     }
   ],
   "transforms": [
@@ -57,7 +46,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [8, 8, 0, 1]
+        [23, 23, 0, 1]
       ]
     },
     {
@@ -67,7 +56,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
+        [9, 9, 0, 1]
       ]
     },
     {
@@ -77,31 +66,11 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [8, 8, 0, 1]
-      ]
-    },
-    {
-      "id": 4,
-      "parent": 3,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [1, 1, 0, 1]
-      ]
-    },
-    {
-      "id": 5,
-      "parent": 4,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [18, 10, 0, 1]
       ]
     },
     {
-      "id": 6,
+      "id": 4,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
@@ -110,8 +79,8 @@
       ]
     },
     {
-      "id": 7,
-      "parent": 6,
+      "id": 5,
+      "parent": 4,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/overlapped-iframe-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/overlapped-iframe-expected.txt
index 32bb4be1d..263d5a33 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/overlapped-iframe-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/overlapped-iframe-expected.txt
@@ -7,30 +7,24 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME id='parent-iframe'",
-      "position": [-30, -30],
-      "bounds": [390, 240],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [285, 230],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [285, 0],
       "bounds": [15, 150],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='overlay'",
@@ -46,7 +40,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [28, 28, 0, 1]
+        [43, 43, 0, 1]
       ]
     },
     {
@@ -56,16 +50,6 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
-      ]
-    },
-    {
-      "id": 3,
-      "parent": 2,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [18, 10, 0, 1]
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/overlapped-iframe-iframe-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/overlapped-iframe-iframe-expected.txt
index a614b84..33c202f 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/overlapped-iframe-iframe-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/overlapped-iframe-iframe-expected.txt
@@ -7,10 +7,6 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame (positioned) IFRAME",
-      "bounds": [304, 304]
-    },
-    {
       "name": "LayoutView #document",
       "bounds": [300, 300],
       "contentsOpaqueForText": true,
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/overlapped-nested-iframes-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/overlapped-nested-iframes-expected.txt
index 85700baf..51ee66a 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/overlapped-nested-iframes-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/overlapped-nested-iframes-expected.txt
@@ -8,62 +8,42 @@
       "transform": 1
     },
     {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [284, 204],
+      "name": "LayoutView #document",
+      "bounds": [280, 200],
       "transform": 2
     },
     {
       "name": "LayoutView #document",
-      "bounds": [280, 200],
+      "bounds": [250, 170],
+      "contentsOpaqueForText": true,
+      "backgroundColor": "#C0C0C0",
       "transform": 3
     },
     {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [252, 172],
+      "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
+      "bounds": [210, 210],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
       "transform": 4
     },
     {
       "name": "LayoutView #document",
-      "bounds": [250, 170],
-      "contentsOpaqueForText": true,
-      "backgroundColor": "#C0C0C0",
+      "bounds": [280, 200],
       "transform": 5
     },
     {
-      "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "bounds": [210, 210],
-      "contentsOpaque": true,
-      "backgroundColor": "#0000FF",
-      "transform": 6
-    },
-    {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [284, 204],
-      "transform": 7
-    },
-    {
-      "name": "LayoutView #document",
-      "bounds": [280, 200],
-      "transform": 8
-    },
-    {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [252, 172],
-      "transform": 9
-    },
-    {
       "name": "LayoutView #document",
       "bounds": [250, 170],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 10
+      "transform": 6
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 11
+      "transform": 7
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='banner'",
@@ -94,7 +74,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [20, 150, 0, 1]
+        [22, 152, 0, 1]
       ]
     },
     {
@@ -104,7 +84,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [2, 2, 0, 1]
+        [9, 9, 0, 1]
       ]
     },
     {
@@ -114,17 +94,17 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [8, 8, 0, 1]
+        [18, 10, 0, 1]
       ]
     },
     {
       "id": 5,
-      "parent": 4,
+      "parent": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [1, 1, 0, 1]
+        [22, 376, 0, 1]
       ]
     },
     {
@@ -134,52 +114,12 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [18, 10, 0, 1]
+        [9, 9, 0, 1]
       ]
     },
     {
       "id": 7,
-      "parent": 1,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [20, 374, 0, 1]
-      ]
-    },
-    {
-      "id": 8,
-      "parent": 7,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [2, 2, 0, 1]
-      ]
-    },
-    {
-      "id": 9,
-      "parent": 8,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [8, 8, 0, 1]
-      ]
-    },
-    {
-      "id": 10,
-      "parent": 9,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [1, 1, 0, 1]
-      ]
-    },
-    {
-      "id": 11,
-      "parent": 10,
+      "parent": 6,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/scrolling-iframe-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/scrolling-iframe-expected.txt
index 93f32529..3a691352 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/scrolling-iframe-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/iframes/scrolling-iframe-expected.txt
@@ -7,42 +7,36 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME id='parent-iframe'",
-      "position": [-30, -30],
-      "bounds": [390, 240],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [508, 608],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [200, 200],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 4
+      "transform": 3
     },
     {
       "name": "ContentsLayer for Horizontal Scrollbar Layer",
       "position": [0, 135],
       "bounds": [285, 15],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [285, 0],
       "bounds": [15, 135],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "Scroll Corner Layer",
       "position": [285, 135],
       "bounds": [15, 15],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='overlay'",
@@ -58,7 +52,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [28, 28, 0, 1]
+        [43, 43, 0, 1]
       ]
     },
     {
@@ -68,7 +62,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
+        [-80, -80, 0, 1]
       ]
     },
     {
@@ -78,16 +72,6 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [-80, -80, 0, 1]
-      ]
-    },
-    {
-      "id": 4,
-      "parent": 3,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [108, 100, 0, 1]
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-absolute-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-absolute-expected.txt
index 162857d..828a99fd 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-absolute-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-absolute-expected.txt
@@ -7,10 +7,6 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame (positioned) IFRAME",
-      "bounds": [400, 400]
-    },
-    {
       "name": "LayoutView #document",
       "bounds": [400, 400],
       "contentsOpaqueForText": true,
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt
index 770669a..71ef226 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt
@@ -7,10 +7,6 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame (positioned) IFRAME",
-      "bounds": [400, 400]
-    },
-    {
       "name": "Scrolling Contents Layer",
       "position": [15, 0],
       "bounds": [1000, 1000],
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-fixed-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-fixed-expected.txt
index 162857d..828a99fd 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-fixed-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-fixed-expected.txt
@@ -7,10 +7,6 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame (positioned) IFRAME",
-      "bounds": [400, 400]
-    },
-    {
       "name": "LayoutView #document",
       "bounds": [400, 400],
       "contentsOpaqueForText": true,
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt
index 394e57a..f79a873 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt
@@ -7,10 +7,6 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame (positioned) IFRAME",
-      "bounds": [400, 400]
-    },
-    {
       "name": "Scrolling Contents Layer",
       "position": [15, 0],
       "bounds": [1000, 1000],
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-relative-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-relative-expected.txt
index 470038d..46a521a 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-relative-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/rtl/rtl-iframe-relative-expected.txt
@@ -7,10 +7,6 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame (positioned) IFRAME",
-      "bounds": [400, 400]
-    },
-    {
       "name": "LayoutView #document",
       "bounds": [400, 400]
     },
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index 14ac88e..c58c3c4a 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/compositing/overlap-test-with-filter-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/compositing/overlap-test-with-filter-expected.txt
index 2f4b1ca..2984294 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/compositing/overlap-test-with-filter-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/compositing/overlap-test-with-filter-expected.txt
@@ -7,10 +7,6 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [300, 100]
-    },
-    {
       "name": "LayoutView #document",
       "bounds": [300, 100],
       "contentsOpaqueForText": true,
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/scroll/composited-iframe-scroll-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/scroll/composited-iframe-scroll-repaint-expected.txt
index 88b1be5..13de5d2 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/scroll/composited-iframe-scroll-repaint-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/scroll/composited-iframe-scroll-repaint-expected.txt
@@ -7,33 +7,28 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [304, 154],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [300, 516],
       "contentsOpaqueForText": true,
       "backgroundColor": "#EEEEEE",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow BODY",
       "bounds": [284, 500],
-      "transform": 4
+      "transform": 3
     },
     {
       "name": "Horizontal Scrollbar Layer",
       "position": [0, 150],
       "bounds": [300, 0],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "Vertical Scrollbar Layer",
       "position": [300, 0],
       "bounds": [0, 150],
-      "transform": 2
+      "transform": 1
     }
   ],
   "transforms": [
@@ -43,7 +38,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [8, 8, 0, 1]
+        [10, 10, 0, 1]
       ]
     },
     {
@@ -53,7 +48,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [2, 2, 0, 1]
+        [0, -20, 0, 1]
       ]
     },
     {
@@ -63,16 +58,6 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [0, -20, 0, 1]
-      ]
-    },
-    {
-      "id": 4,
-      "parent": 3,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [8, 8, 0, 1]
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/cascade/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/cascade/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index 14ac88e..c58c3c4a 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/cascade/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/cascade/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
index 426a5af..127c52b 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-revoke-error-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-revoke-error-expected.txt
index ac7fbcf..d58f540 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-revoke-error-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-revoke-error-expected.txt
@@ -6,7 +6,9 @@
 Message added: error log
 
 3 errors
-console-message-wrapper console-error-level x3
+console-message-wrapper console-error-level
+console-message-wrapper console-error-level
+console-message-wrapper console-error-level
 
 Handling promise
 1 error
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-timestamp-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-timestamp-expected.txt
index 274b75a..3b64437c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-timestamp-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-timestamp-expected.txt
@@ -3,7 +3,9 @@
 Console messages with timestamps disabled:
 <Before> First Command
 "<Before> First Result"
-3<Before>
+<Before>
+<Before>
+<Before>
 <Before> Command
 "<Before> Result"
 Console messages with timestamps enabled:
diff --git a/third_party/blink/web_tests/http/tests/devtools/layers/layer-tree-model-expected.txt b/third_party/blink/web_tests/http/tests/devtools/layers/layer-tree-model-expected.txt
index 7684a48..bae4c56 100644
--- a/third_party/blink/web_tests/http/tests/devtools/layers/layer-tree-model-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/layers/layer-tree-model-expected.txt
@@ -3,7 +3,6 @@
 <invalid node id> 0x0 (0)
     #document (1)
     #document (1)
-    iframe#frame (1)
     #document 200x200 (1)
     div#subframe1 80x80 (1)
     div#a 200x200 (1)
@@ -16,7 +15,6 @@
 <invalid node id> 0x0 (0)
     #document (1)
     #document (1)
-    iframe#frame (1)
     #document 200x200 (1)
     div#subframe1 80x80 (1)
     div#a 200x200 (1)
@@ -29,7 +27,6 @@
 <invalid node id> 0x0 (0)
     #document (1)
     #document (1)
-    iframe#frame (1)
     #document 200x200 (1)
     div#subframe1 80x80 (1)
     div#a 200x200 (1)
diff --git a/third_party/blink/web_tests/http/tests/devtools/profiler/heap-snapshot-loader.js b/third_party/blink/web_tests/http/tests/devtools/profiler/heap-snapshot-loader.js
index 774d1ce..47196380 100644
--- a/third_party/blink/web_tests/http/tests/devtools/profiler/heap-snapshot-loader.js
+++ b/third_party/blink/web_tests/http/tests/devtools/profiler/heap-snapshot-loader.js
@@ -18,7 +18,7 @@
 
     var profileType = Profiler.ProfileTypeRegistry.instance.heapSnapshotProfileType;
 
-    TestRunner.override(TestRunner.HeapProfilerAgent, 'takeHeapSnapshot', takeHeapSnapshotMock);
+    TestRunner.override(TestRunner.HeapProfilerAgent, 'invoke_takeHeapSnapshot', takeHeapSnapshotMock);
     function takeHeapSnapshotMock(reportProgress) {
       if (reportProgress) {
         profileType._reportHeapSnapshotProgress({data: {done: 50, total: 100, finished: false}});
diff --git a/third_party/blink/web_tests/http/tests/eventsource/eventsource-cors-non-http-expected.txt b/third_party/blink/web_tests/http/tests/eventsource/eventsource-cors-non-http-expected.txt
index 389dca8..148dede 100644
--- a/third_party/blink/web_tests/http/tests/eventsource/eventsource-cors-non-http-expected.txt
+++ b/third_party/blink/web_tests/http/tests/eventsource/eventsource-cors-non-http-expected.txt
@@ -1,7 +1,7 @@
 CONSOLE WARNING: Subresource requests using legacy protocols (like `ftp:`) are blocked. Please deliver web-accessible resources over modern protocols like HTTPS. See https://www.chromestatus.com/feature/5709390967472128 for details.
 CONSOLE ERROR: Not allowed to load local resource: motd
-CONSOLE ERROR: Access to resource at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Access to resource at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to resource at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: Access to resource at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
 Test EventSource with non-HTTP protocol schemes in the URL.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/blink/web_tests/http/tests/eventsource/workers/eventsource-cors-non-http-expected.txt b/third_party/blink/web_tests/http/tests/eventsource/workers/eventsource-cors-non-http-expected.txt
index c7f7c27..b443b28 100644
--- a/third_party/blink/web_tests/http/tests/eventsource/workers/eventsource-cors-non-http-expected.txt
+++ b/third_party/blink/web_tests/http/tests/eventsource/workers/eventsource-cors-non-http-expected.txt
@@ -1,8 +1,8 @@
 CONSOLE WARNING: Subresource requests using legacy protocols (like `ftp:`) are blocked. Please deliver web-accessible resources over modern protocols like HTTPS. See https://www.chromestatus.com/feature/5709390967472128 for details.
 CONSOLE WARNING: Subresource requests using legacy protocols (like `ftp:`) are blocked. Please deliver web-accessible resources over modern protocols like HTTPS. See https://www.chromestatus.com/feature/5709390967472128 for details.
 CONSOLE ERROR: Not allowed to load local resource: motd
-CONSOLE ERROR: Access to resource at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Access to resource at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to resource at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: Access to resource at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
 [Worker] Test EventSource with non-HTTP protocol schemes in the URL.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/blink/web_tests/http/tests/fetch/script-tests/fetch_upload.js b/third_party/blink/web_tests/http/tests/fetch/script-tests/fetch_upload.js
index d1ac948..9505637e 100644
--- a/third_party/blink/web_tests/http/tests/fetch/script-tests/fetch_upload.js
+++ b/third_party/blink/web_tests/http/tests/fetch/script-tests/fetch_upload.js
@@ -2,6 +2,8 @@
   importScripts('../resources/fetch-test-helpers.js');
 }
 
+var {BASE_ORIGIN, OTHER_ORIGIN} = get_fetch_test_options();
+
 function fetch_echo(stream) {
   return fetch(
       '/serviceworker/resources/fetch-echo-body.php',
@@ -23,19 +25,17 @@
   });
 }
 
-promise_test(() => {
+promise_test(async () => {
   const stream =
       create_stream(['Foo', 'Bar']).pipeThrough(new TextEncoderStream());
-  return fetch_echo_body(stream).then(function(text) {
-    assert_equals(text, 'FooBar');
-  });
+  const text = await fetch_echo_body(stream);
+  assert_equals(text, 'FooBar');
 }, 'Fetch with ReadableStream body with Uint8Array');
 
-promise_test(() => {
+promise_test(async () => {
   const stream = create_stream([new Uint8Array(0)]);
-  return fetch_echo_body(stream).then(function(text) {
-    assert_equals(text, '');
-  });
+  const text = await fetch_echo_body(stream);
+  assert_equals(text, '');
 }, 'Fetch with ReadableStream body with empty Uint8Array');
 
 function random_values_array(length) {
@@ -94,4 +94,23 @@
   await promise_rejects_js(t, TypeError, fetch_echo(stream));
 }, 'Fetch with ReadableStream body containing number should fail');
 
+function fetch_redirect(status) {
+  const redirect_target_url =
+      BASE_ORIGIN + '/fetch/resources/fetch-status.php?status=200';
+  const redirect_original_url = BASE_ORIGIN +
+      '/serviceworker/resources/redirect.php?Redirect=' + redirect_target_url;
+  const stream = create_stream(['Foo']).pipeThrough(new TextEncoderStream());
+  return fetch(
+      redirect_original_url + `&Status=${status}`,
+      {method: 'POST', body: stream});
+}
+
+promise_test(async (t) => {
+  await fetch_redirect(303);
+}, 'Fetch upload stream should success on 303(See Other) code');
+
+promise_test(async (t) => {
+  await promise_rejects_js(t, TypeError, fetch_redirect(307));
+}, 'Fetch upload stream should fail on non-303 redirect code');
+
 done();
diff --git a/third_party/blink/web_tests/http/tests/xmlhttprequest/cross-origin-unsupported-url-expected.txt b/third_party/blink/web_tests/http/tests/xmlhttprequest/cross-origin-unsupported-url-expected.txt
index 45a0a6b9..449205a5 100644
--- a/third_party/blink/web_tests/http/tests/xmlhttprequest/cross-origin-unsupported-url-expected.txt
+++ b/third_party/blink/web_tests/http/tests/xmlhttprequest/cross-origin-unsupported-url-expected.txt
@@ -1,16 +1,16 @@
 CONSOLE WARNING: line 8: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
 This is a testharness.js-based test.
 PASS sync test for url=mailto:foo@bar.com, contentType=undefined
 PASS sync test for url=mailto:foo@bar.com, contentType=application/json
diff --git a/third_party/blink/web_tests/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt b/third_party/blink/web_tests/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt
index 785ec72..a8031b4 100644
--- a/third_party/blink/web_tests/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt
+++ b/third_party/blink/web_tests/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt
@@ -1,15 +1,15 @@
-CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
 This is a testharness.js-based test.
 PASS sync test for url=mailto:foo@bar.com, contentType=undefined
 PASS sync test for url=mailto:foo@bar.com, contentType=application/json
diff --git a/third_party/blink/web_tests/mhtml/cid_in_html_resource-expected.txt b/third_party/blink/web_tests/mhtml/cid_in_html_resource-expected.txt
index c54c22f..9ce2af1 100644
--- a/third_party/blink/web_tests/mhtml/cid_in_html_resource-expected.txt
+++ b/third_party/blink/web_tests/mhtml/cid_in_html_resource-expected.txt
@@ -1,2 +1,2 @@
-CONSOLE ERROR: Access to font at 'cid:xxxxxx' from origin '' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to font at 'cid:xxxxxx' from origin '' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-untrusted, https.
 No Content-ID url are expected outside of an MHTML document. The document should load without crashing.
diff --git a/third_party/blink/web_tests/paint/invalidation/compositing/overlap-test-with-filter-expected.txt b/third_party/blink/web_tests/paint/invalidation/compositing/overlap-test-with-filter-expected.txt
index 4a384b5..e04c5380 100644
--- a/third_party/blink/web_tests/paint/invalidation/compositing/overlap-test-with-filter-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/compositing/overlap-test-with-filter-expected.txt
@@ -7,10 +7,6 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [300, 100]
-    },
-    {
       "name": "LayoutView #document",
       "bounds": [300, 100],
       "contentsOpaqueForText": true,
diff --git a/third_party/blink/web_tests/paint/invalidation/scroll/composited-iframe-scroll-repaint-expected.txt b/third_party/blink/web_tests/paint/invalidation/scroll/composited-iframe-scroll-repaint-expected.txt
index 32b322a..88c132ec 100644
--- a/third_party/blink/web_tests/paint/invalidation/scroll/composited-iframe-scroll-repaint-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/scroll/composited-iframe-scroll-repaint-expected.txt
@@ -7,33 +7,28 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [304, 154],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [300, 516],
       "contentsOpaqueForText": true,
       "backgroundColor": "#EEEEEE",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "LayoutNGBlockFlow BODY",
       "bounds": [284, 500],
-      "transform": 4
+      "transform": 3
     },
     {
       "name": "Horizontal Scrollbar Layer",
       "position": [0, 150],
       "bounds": [300, 0],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "Vertical Scrollbar Layer",
       "position": [300, 0],
       "bounds": [0, 150],
-      "transform": 2
+      "transform": 1
     }
   ],
   "transforms": [
@@ -43,7 +38,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [8, 8, 0, 1]
+        [10, 10, 0, 1]
       ]
     },
     {
@@ -53,7 +48,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [2, 2, 0, 1]
+        [0, -20, 0, 1]
       ]
     },
     {
@@ -63,16 +58,6 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [0, -20, 0, 1]
-      ]
-    },
-    {
-      "id": 4,
-      "parent": 3,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [8, 8, 0, 1]
       ]
     }
diff --git a/third_party/blink/web_tests/paint/invalidation/scroll/repaint-during-scroll-with-zoom-expected.txt b/third_party/blink/web_tests/paint/invalidation/scroll/repaint-during-scroll-with-zoom-expected.txt
index 60dba74..4bb2645e 100644
--- a/third_party/blink/web_tests/paint/invalidation/scroll/repaint-during-scroll-with-zoom-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/scroll/repaint-during-scroll-with-zoom-expected.txt
@@ -7,34 +7,29 @@
       "backgroundColor": "#C0C0C0"
     },
     {
-      "name": "LayoutIFrame (positioned) IFRAME",
-      "bounds": [255, 255],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [2008, 2016],
       "contentsOpaqueForText": true,
       "backgroundColor": "#FFFFFF",
-      "transform": 3
+      "transform": 2
     },
     {
       "name": "ContentsLayer for Horizontal Scrollbar Layer",
       "position": [0, 235],
       "bounds": [235, 15],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [235, 0],
       "bounds": [15, 235],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "Scroll Corner Layer",
       "position": [235, 235],
       "bounds": [15, 15],
-      "transform": 2
+      "transform": 1
     }
   ],
   "transforms": [
@@ -44,7 +39,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [0, 63, 0, 1]
+        [3, 65, 0, 1]
       ]
     },
     {
@@ -54,16 +49,6 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [3, 2, 0, 1]
-      ]
-    },
-    {
-      "id": 3,
-      "parent": 2,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [-10, -10, 0, 1]
       ]
     }
diff --git a/third_party/blink/web_tests/platform/linux/compositing/overflow/border-radius-composited-subframe-expected.png b/third_party/blink/web_tests/platform/linux/compositing/overflow/border-radius-composited-subframe-expected.png
index c0ec3b0..ca07de2 100644
--- a/third_party/blink/web_tests/platform/linux/compositing/overflow/border-radius-composited-subframe-expected.png
+++ b/third_party/blink/web_tests/platform/linux/compositing/overflow/border-radius-composited-subframe-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/backgrounds/background-position-parsing-expected.png b/third_party/blink/web_tests/platform/linux/fast/backgrounds/background-position-parsing-expected.png
index 44c33b1..ff6aac0 100644
--- a/third_party/blink/web_tests/platform/linux/fast/backgrounds/background-position-parsing-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/backgrounds/background-position-parsing-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index 09943e751..c7259b6 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/sub-pixel/transformed-iframe-copy-on-scroll-expected.png b/third_party/blink/web_tests/platform/linux/fast/sub-pixel/transformed-iframe-copy-on-scroll-expected.png
index 6740e5ac7..68cb6014 100644
--- a/third_party/blink/web_tests/platform/linux/fast/sub-pixel/transformed-iframe-copy-on-scroll-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/sub-pixel/transformed-iframe-copy-on-scroll-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/cascade/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/platform/linux/virtual/cascade/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index 09943e751..c7259b6 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/cascade/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/cascade/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png
index 77bb884..83da2b90 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png
index 5ddf95a..72c41260 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
index 8f2adc3..03f5a821 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
index 704bdfb..3c627bd8 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
index 5708d62..1960aff5 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
index 214b9f1..bf33af9 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png
index 042e961..4360fc75 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png
index 46864c4..573c26a 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
index 9b5bde4..86400da 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
index cd8b0c5..8c2a2b45 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
index 9a50b4ae..5b79c767 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/month-picker/month-picker-appearance-zoom150-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/month-picker/month-picker-appearance-zoom150-expected.png
index 2eb309c..3bc81b3 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/month-picker/month-picker-appearance-zoom150-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/month-picker/month-picker-appearance-zoom150-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/border-radius-composited-subframe-expected.png b/third_party/blink/web_tests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/border-radius-composited-subframe-expected.png
index c0ec3b0..ca07de2 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/border-radius-composited-subframe-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/border-radius-composited-subframe-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/blink/web_tests/platform/linux/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
index fdda9b7c..0fc1b81 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png b/third_party/blink/web_tests/platform/linux/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
index d070542d..3b77b9b 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
index 750f38e..167864b 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
index 8686a90..876ecc0 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
index ae0f59b..009b41b 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
index 6207cf2..8c81ed34 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
index 750f38e..167864b 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
index 8686a90..876ecc0 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
index ae0f59b..009b41b 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
index 5b296160..733211b 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/compositing/iframes/invisible-nested-iframe-show-expected.txt b/third_party/blink/web_tests/platform/mac/compositing/iframes/invisible-nested-iframe-show-expected.txt
index 89de0cee..604dcc8 100644
--- a/third_party/blink/web_tests/platform/mac/compositing/iframes/invisible-nested-iframe-show-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/compositing/iframes/invisible-nested-iframe-show-expected.txt
@@ -7,47 +7,36 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME",
-      "position": [-30, -30],
-      "bounds": [390, 240],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [285, 192],
-      "transform": 2
-    },
-    {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [252, 172],
-      "transform": 3
+      "transform": 1
     },
     {
       "name": "LayoutView #document",
       "bounds": [250, 170],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 4
+      "transform": 2
     },
     {
       "name": "LayoutNGBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 5
+      "transform": 3
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [285, 0],
       "bounds": [15, 150],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutNGBlockFlow DIV class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 7
+      "transform": 5
     }
   ],
   "transforms": [
@@ -57,7 +46,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [8, 8, 0, 1]
+        [23, 23, 0, 1]
       ]
     },
     {
@@ -67,7 +56,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
+        [9, 9, 0, 1]
       ]
     },
     {
@@ -77,31 +66,11 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [8, 8, 0, 1]
-      ]
-    },
-    {
-      "id": 4,
-      "parent": 3,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [1, 1, 0, 1]
-      ]
-    },
-    {
-      "id": 5,
-      "parent": 4,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [18, 10, 0, 1]
       ]
     },
     {
-      "id": 6,
+      "id": 4,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
@@ -110,8 +79,8 @@
       ]
     },
     {
-      "id": 7,
-      "parent": 6,
+      "id": 5,
+      "parent": 4,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/mathml/presentation-markup/mpadded/mpadded-002-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/mathml/presentation-markup/mpadded/mpadded-002-expected.txt
new file mode 100644
index 0000000..bbddd957
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/mathml/presentation-markup/mpadded/mpadded-002-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+FAIL mpadded with no attributes assert_approx_equals: content height expected 150 +/- 1 but got -4
+FAIL Different widths assert_approx_equals: width 0 expected 25 +/- 1 but got 100
+FAIL Different heights assert_approx_equals: height0 expected 25 +/- 1 but got -4
+FAIL Different depths assert_approx_equals: height0 expected 150 +/- 1 but got -4
+FAIL Various combinations of height, depth and width. assert_approx_equals: width0 expected 25 +/- 1 but got 100
+PASS Preferred width
+PASS dynamic attributes (remove)
+FAIL dynamic attributes (attach) assert_approx_equals: expected 50 +/- 1 but got 100
+FAIL dynamic attributes (modify) assert_approx_equals: expected 50 +/- 1 but got 100
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac/fast/backgrounds/background-position-parsing-expected.png b/third_party/blink/web_tests/platform/mac/fast/backgrounds/background-position-parsing-expected.png
index 7b27bb58..67e0526 100644
--- a/third_party/blink/web_tests/platform/mac/fast/backgrounds/background-position-parsing-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/backgrounds/background-position-parsing-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/sub-pixel/transformed-iframe-copy-on-scroll-expected.png b/third_party/blink/web_tests/platform/mac/fast/sub-pixel/transformed-iframe-copy-on-scroll-expected.png
index 8d59a46..351f227 100644
--- a/third_party/blink/web_tests/platform/mac/fast/sub-pixel/transformed-iframe-copy-on-scroll-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/sub-pixel/transformed-iframe-copy-on-scroll-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-lr-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-lr-expected.txt
index 458670f..1bb24bd 100644
--- a/third_party/blink/web_tests/platform/mac/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-lr-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-lr-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [7, 8, 33, 48]
+        [8, 8, 33, 48]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png
deleted file mode 100644
index 35ca352..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png
deleted file mode 100644
index ebd04b0..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
deleted file mode 100644
index b15ee0e..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
deleted file mode 100644
index 4d8c9d83d..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
deleted file mode 100644
index 577d9f9..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
index 1a368c0..f2da118 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
index b15ee0e..4183d1ee 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
index 4d8c9d83d..4e9f9fc0 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
index 577d9f9..985fcf3 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/compositing/iframes/invisible-nested-iframe-show-expected.txt b/third_party/blink/web_tests/platform/win/compositing/iframes/invisible-nested-iframe-show-expected.txt
index e66a738..dcaeae4a 100644
--- a/third_party/blink/web_tests/platform/win/compositing/iframes/invisible-nested-iframe-show-expected.txt
+++ b/third_party/blink/web_tests/platform/win/compositing/iframes/invisible-nested-iframe-show-expected.txt
@@ -7,47 +7,36 @@
       "backgroundColor": "#FFFFFF"
     },
     {
-      "name": "LayoutIFrame IFRAME",
-      "position": [-30, -30],
-      "bounds": [390, 240],
-      "transform": 1
-    },
-    {
       "name": "Scrolling Contents Layer",
       "bounds": [285, 193],
-      "transform": 2
-    },
-    {
-      "name": "LayoutIFrame IFRAME",
-      "bounds": [252, 172],
-      "transform": 3
+      "transform": 1
     },
     {
       "name": "LayoutView #document",
       "bounds": [250, 170],
       "contentsOpaqueForText": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 4
+      "transform": 2
     },
     {
       "name": "LayoutNGBlockFlow DIV id='iframe-content' class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 5
+      "transform": 3
     },
     {
       "name": "ContentsLayer for Vertical Scrollbar Layer",
       "position": [285, 0],
       "bounds": [15, 150],
-      "transform": 2
+      "transform": 1
     },
     {
       "name": "LayoutNGBlockFlow DIV class='box'",
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 7
+      "transform": 5
     }
   ],
   "transforms": [
@@ -57,7 +46,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [8, 8, 0, 1]
+        [23, 23, 0, 1]
       ]
     },
     {
@@ -67,7 +56,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [15, 15, 0, 1]
+        [9, 9, 0, 1]
       ]
     },
     {
@@ -77,31 +66,11 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [8, 8, 0, 1]
-      ]
-    },
-    {
-      "id": 4,
-      "parent": 3,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [1, 1, 0, 1]
-      ]
-    },
-    {
-      "id": 5,
-      "parent": 4,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
         [18, 10, 0, 1]
       ]
     },
     {
-      "id": 6,
+      "id": 4,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
@@ -110,8 +79,8 @@
       ]
     },
     {
-      "id": 7,
-      "parent": 6,
+      "id": 5,
+      "parent": 4,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/mathml/presentation-markup/mpadded/mpadded-002-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/mathml/presentation-markup/mpadded/mpadded-002-expected.txt
new file mode 100644
index 0000000..cb9f06d
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/external/wpt/mathml/presentation-markup/mpadded/mpadded-002-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+FAIL mpadded with no attributes assert_approx_equals: content height expected 150 +/- 1 but got -5
+FAIL Different widths assert_approx_equals: width 0 expected 25 +/- 1 but got 100
+FAIL Different heights assert_approx_equals: height0 expected 25 +/- 1 but got -5
+FAIL Different depths assert_approx_equals: height0 expected 150 +/- 1 but got -5
+FAIL Various combinations of height, depth and width. assert_approx_equals: width0 expected 25 +/- 1 but got 100
+PASS Preferred width
+PASS dynamic attributes (remove)
+FAIL dynamic attributes (attach) assert_approx_equals: expected 50 +/- 1 but got 100
+FAIL dynamic attributes (modify) assert_approx_equals: expected 50 +/- 1 but got 100
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win/fast/backgrounds/background-position-parsing-expected.png b/third_party/blink/web_tests/platform/win/fast/backgrounds/background-position-parsing-expected.png
index f14a3a1..0deb5ad 100644
--- a/third_party/blink/web_tests/platform/win/fast/backgrounds/background-position-parsing-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/backgrounds/background-position-parsing-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index e35c44b4..aa4987f 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/sub-pixel/transformed-iframe-copy-on-scroll-expected.png b/third_party/blink/web_tests/platform/win/fast/sub-pixel/transformed-iframe-copy-on-scroll-expected.png
index 50c75da2..b2f37ce 100644
--- a/third_party/blink/web_tests/platform/win/fast/sub-pixel/transformed-iframe-copy-on-scroll-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/sub-pixel/transformed-iframe-copy-on-scroll-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png
index d875acd..60158ab 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png
index 6eb2d52..7b3a18c 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
index 45ccc0e..5f7cc67 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
index ab4596b84..5dfbc84 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
index f873bee..647e871 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
index 639ece2a..76b4e75 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png
index 762a80e..d3d858b5 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/date/date-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png
index c32070fd..af45de7 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
index 0fd0905..fff163e 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
index ce4b91a..5882a15 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/time/time-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
index b812801b..e2ac4e5 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/week/week-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/month-picker/month-picker-appearance-zoom150-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/month-picker/month-picker-appearance-zoom150-expected.png
index 0ea1a3a..6f7ece7 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/month-picker/month-picker-appearance-zoom150-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/month-picker/month-picker-appearance-zoom150-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/blink/web_tests/platform/win/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
index 6d84518..319abcdd 100644
--- a/third_party/blink/web_tests/platform/win/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index cd2810c..ef2bebab 100644
--- a/third_party/blink/web_tests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/cascade/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/platform/win7/virtual/cascade/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index cd2810c..ef2bebab 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/cascade/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/cascade/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
index 34488cf..2d67748 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
index 15978d8..b2d1ff1 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
index fe9c5af..dfc1895 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/color-scheme/month/month-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/month-picker/month-picker-appearance-zoom150-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/month-picker/month-picker-appearance-zoom150-expected.png
index 08b9ddb..666d858 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/month-picker/month-picker-appearance-zoom150-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/month-picker/month-picker-appearance-zoom150-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/blink/web_tests/platform/win7/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
index a6cfebf0..4fb1029 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/pointer-lock/wheel-event-target.html b/third_party/blink/web_tests/pointer-lock/wheel-event-target.html
new file mode 100644
index 0000000..2215c75
--- /dev/null
+++ b/third_party/blink/web_tests/pointer-lock/wheel-event-target.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<head>
+  <link rel="help" href="https://w3c.github.io/pointerlock/#extensions-to-the-element-interface">
+  <script src="../resources/testharness.js"></script>
+  <script src="../resources/testharnessreport.js"></script>
+  <script src="../resources/gesture-util.js"></script>
+</head>
+<body>
+<h1>Verify wheel events are sent to the pointerlock target instead of the hittest element when pointer is locked</h1>
+
+<canvas id="target" style="touch-action:none" width="640" height="360">
+  Your browser does not support HTML5 canvas
+</canvas>
+
+<div id="text">
+  Click here to lock the pointer.
+  Using mousewheel in this area when pointer is locked should direct wheel
+  events to target.
+</div>
+
+<script type="text/javascript">
+  let target = document.getElementById("target");
+  let textDiv = document.getElementById("text");
+  let didTargetReceiveWheel = false;
+
+  textDiv.addEventListener("click",()=>{
+    target.requestPointerLock();
+  });
+
+  async function runTest(){
+   target.addEventListener("wheel",()=>{
+    didTargetReceiveWheel = true;
+   });
+
+   textDiv.addEventListener("wheel",
+      testObject.unreached_func("wheel event should not fire on element with id = text!"));
+
+   let rect = textDiv.getBoundingClientRect();
+   let x = rect.left;
+   let y = rect.top;
+   await mouseMoveTo(x, y);
+   await smoothScrollWithXY(5, 5, x, y, GestureSourceType.MOUSE_INPUT, SPEED_INSTANT);
+
+   if(didTargetReceiveWheel)
+     testPromiseResolve();
+   else
+     testPromiseReject("wheel event should fire on element with id = target !");
+  }
+
+  let testPromiseResolve;
+  let testPromiseReject;
+  let testObject;
+  promise_test(function(test){
+    return new Promise(async (resolve,reject)=>{
+     testPromiseResolve = resolve;
+     testPromiseReject = reject;
+     testObject = test;
+     let runTestFirstPointerLockChange = true;
+
+     document.addEventListener("pointerlockchange", async (e)=>{
+       if(runTestFirstPointerLockChange){
+          runTestFirstPointerLockChange = false;
+          await runTest();
+       }
+     });
+     document.addEventListener("pointerlockerror",
+       test.unreached_func("PointerLock should succeed!"));
+
+     let rect = textDiv.getBoundingClientRect();
+     let x = rect.left;
+     let y = rect.top;
+
+     await mouseMoveTo(x,y);
+     await mouseClickOn(x,y);
+   });
+  });
+</script>
+</body>
diff --git a/third_party/blink/web_tests/transforms/2d/transform-2d-expected.txt b/third_party/blink/web_tests/transforms/2d/transform-2d-expected.txt
deleted file mode 100644
index 1fbea47..0000000
--- a/third_party/blink/web_tests/transforms/2d/transform-2d-expected.txt
+++ /dev/null
@@ -1,84 +0,0 @@
-transform "none" expected "none" : PASS
-transform "" expected "matrix(5.96046e-08, 1, -1, 5.96046e-08, 0, 0)" : PASS
-transform "inherit" expected "none" : PASS
-transform "translate(80px, 90px)" expected "matrix(1, 0, 0, 1, 80, 90)" : PASS
-transform "translate(100%, 3em)" expected "matrix(1, 0, 0, 1, 200, 48)" : PASS
-transform "translate(50px)" expected "matrix(1, 0, 0, 1, 50, 0)" : PASS
-transform "translatex(-20px)" expected "matrix(1, 0, 0, 1, -20, 0)" : PASS
-transform "translateX(-20px)" expected "matrix(1, 0, 0, 1, -20, 0)" : PASS
-transform "translatey(23px)" expected "matrix(1, 0, 0, 1, 0, 23)" : PASS
-transform "translateY(-3em)" expected "matrix(1, 0, 0, 1, 0, -48)" : PASS
-transform "scale(1.2)" expected "matrix(1.2, 0, 0, 1.2, 0, 0)" : PASS
-transform "scalex(1.5)" expected "matrix(1.5, 0, 0, 1, 0, 0)" : PASS
-transform "scaleX(1.5)" expected "matrix(1.5, 0, 0, 1, 0, 0)" : PASS
-transform "scaley(1.5)" expected "matrix(1, 0, 0, 1.5, 0, 0)" : PASS
-transform "scaleY(1.5)" expected "matrix(1, 0, 0, 1.5, 0, 0)" : PASS
-transform "scale(1.2, 0.8)" expected "matrix(1.2, 0, 0, 0.8, 0, 0)" : PASS
-transform "scale(-1.2, -0.8)" expected "matrix(-1.2, -0, -0, -0.8, 0, 0)" : PASS
-transform "skew(-0.7rad, 20deg)" expected "matrix(1, 0.36397, -0.842288, 1, 0, 0)" : PASS
-transform "skew(12grad)" expected "matrix(1, 0, 0.19076, 1, 0, 0)" : PASS
-transform "skewx(12grad)" expected "matrix(1, 0, 0.19076, 1, 0, 0)" : PASS
-transform "skewX(12grad)" expected "matrix(1, 0, 0.19076, 1, 0, 0)" : PASS
-transform "skewy(-12grad)" expected "matrix(1, -0.19076, 0, 1, 0, 0)" : PASS
-transform "skewY(-12grad)" expected "matrix(1, -0.19076, 0, 1, 0, 0)" : PASS
-transform "skewx(0.1turn)" expected "matrix(1, 0, 0.726543, 1, 0, 0)" : PASS
-transform "rotate(45deg)" expected "matrix(0.707107, 0.707107, -0.707107, 0.707107, 0, 0)" : PASS
-transform "rotate(90deg)" expected "matrix(-4.37114e-08, 1, -1, -4.37114e-08, 0, 0)" : PASS
-transform "rotate(-90deg)" expected "matrix(-4.37114e-08, -1, 1, -4.37114e-08, 0, 0)" : PASS
-transform "rotate(180deg)" expected "matrix(-1, -8.74228e-08, 8.74228e-08, -1, 0, 0)" : PASS
-transform "rotate(1.2rad)" expected "matrix(0.362358, 0.932039, -0.932039, 0.362358, 0, 0)" : PASS
-transform "rotate(0.25turn)" expected "matrix(-4.37114e-08, 1, -1, -4.37114e-08, 0, 0)" : PASS
-transform "rotate(0.5turn)" expected "matrix(-1, -8.74228e-08, 8.74228e-08, -1, 0, 0)" : PASS
-transform "rotate(1.5turn)" expected "matrix(-1, -8.74228e-08, 8.74228e-08, -1, 0, 0)" : PASS
-transform "matrix(1, 0, 0, 1, 0, 0)" expected "matrix(1, 0, 0, 1, 0, 0)" : PASS
-transform "matrix(1, -0.19076, 0, 1, 0, 0)" expected "matrix(1, -0.19076, 0, 1, 0, 0)" : PASS
-transform "matrix(0.2, 0.3, 0.4, 1.1, 1.2, 1.3)" expected "matrix(0.2, 0.3, 0.4, 1.1, 1.2, 1.3)" : PASS
-transform ",rotate(12deg)" expected "none" : PASS
-transform "rotate(12deg)," expected "none" : PASS
-transform "rotate(12deg) +" expected "none" : PASS
-transform "(translate(50, 20))" expected "none" : PASS
-transform "eggs(10)" expected "none" : PASS
-transform "translate(50, 20)" expected "none" : PASS
-transform "translate()" expected "none" : PASS
-transform "translate(10px, 20px, 30px)" expected "none" : PASS
-transform "translate(10px, 20px, 30px, 40px)" expected "none" : PASS
-transform "translate(10smidgens)" expected "none" : PASS
-transform "translate(10px, 10smidgens)" expected "none" : PASS
-transform "translateX(10px, 20px)" expected "none" : PASS
-transform "translateX(10px, 20px, 30px)" expected "none" : PASS
-transform "translateX(10smidgens)" expected "none" : PASS
-transform "translateX(10px, 10smidgens)" expected "none" : PASS
-transform "translateY(10px, 20px)" expected "none" : PASS
-transform "translateY(10px, 20px, 30px)" expected "none" : PASS
-transform "translateY(10smidgens)" expected "none" : PASS
-transform "translateY(10px, 10smidgens)" expected "none" : PASS
-transform "scale(2px, 2px)" expected "none" : PASS
-transform "scale(2, 2px)" expected "none" : PASS
-transform "scale()" expected "none" : PASS
-transform "scale(1, 2, 3)" expected "none" : PASS
-transform "scale(2smidgens)" expected "none" : PASS
-transform "scale(2, 2smidgens)" expected "none" : PASS
-transform "rotate(10)" expected "none" : PASS
-transform "rotate()" expected "none" : PASS
-transform "rotate(10deg, 20deg)" expected "none" : PASS
-transform "rotate(2turns)" expected "none" : PASS
-transform "rotate(2spins)" expected "none" : PASS
-transform "rotate(2, 2spins)" expected "none" : PASS
-transform "skew(10)" expected "none" : PASS
-transform "skew()" expected "none" : PASS
-transform "skew(10deg, 20deg, 30deg)" expected "none" : PASS
-transform "skew(2bits)" expected "none" : PASS
-transform "skew(2, 2bits)" expected "none" : PASS
-transform "skewX(10)" expected "none" : PASS
-transform "skewX()" expected "none" : PASS
-transform "skewX(10deg, 20deg)" expected "none" : PASS
-transform "skewX(2bits)" expected "none" : PASS
-transform "skewY(10)" expected "none" : PASS
-transform "skewY()" expected "none" : PASS
-transform "skewY(10deg, 20deg)" expected "none" : PASS
-transform "skewY(2bits)" expected "none" : PASS
-transform "matrix()" expected "none" : PASS
-transform "matrix(2, 0, 0, 2)" expected "none" : PASS
-transform "matrix(0.978148, 0.207912, -0.207912, 0.978148, 50, 20, 666)" expected "none" : PASS
-transform "matrix(1, 0, 0, 1, 20px, 50px)" expected "none" : PASS
-
diff --git a/third_party/blink/web_tests/transforms/2d/transform-2d.html b/third_party/blink/web_tests/transforms/2d/transform-2d.html
index c4dc417..f782d02e 100644
--- a/third_party/blink/web_tests/transforms/2d/transform-2d.html
+++ b/third_party/blink/web_tests/transforms/2d/transform-2d.html
@@ -1,160 +1,147 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
-   "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/transform-test-utils.js"></script>
+<style>
+  .container {
+    height: 100px;
+    width: 200px;
+    margin: 30px;
+    outline: 1px solid black;
+  }
+  .box {
+    height: 100%;
+    width: 100%;
+    background-color: green;
+    transform: rotate(90deg);
+  }
+</style>
+<div class="container">
+  <div id="test-box" class="box"></div>
+</div>
+<script>
 
-<html lang="en">
-<head>
-  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-  <title>2D Transform Tests</title>
-  <style type="text/css" media="screen">
-    .container {
-      height: 100px;
-      width: 200px;
-      margin: 30px;
-      outline: 1px solid black;
-    }
-    .box {
-      height: 100%;
-      width: 100%;
-      background-color: green;
-      transform: rotate(90deg);
-    }
-    #results {
-      margin-top: 100px;
-    }
-  </style>
-  <script src="resources/transform-test-utils.js" type="text/javascript" charset="utf-8"></script>
-  <script type="text/javascript" charset="utf-8">
-    if (window.testRunner) {
-      testRunner.dumpAsText();
-      testRunner.waitUntilDone();
-    }
+const gTests = [
+  // nothing
+  { 'transform' : 'none', 'result' : 'none' },
+  { 'transform' : '', 'result' : 'matrix(5.96046e-08, 1, -1, 5.96046e-08, 0, 0)' }, // this cancels the style - revert back to box
+  { 'transform' : 'inherit', 'result' : 'none' }, // parent element doesn't have transform
 
-    var gTests = [
-      // nothing
-      { 'transform' : 'none', 'result' : 'none' },
-      { 'transform' : '', 'result' : 'matrix(5.96046e-08, 1, -1, 5.96046e-08, 0, 0)' }, // this cancels the style - revert back to box
-      { 'transform' : 'inherit', 'result' : 'none' }, // parent element doesn't have transform
+  // translate
+  { 'transform' : 'translate(80px, 90px)',  'result' : 'matrix(1, 0, 0, 1, 80, 90)' },
+  { 'transform' : 'translate(100%, 3em)',   'result' : 'matrix(1, 0, 0, 1, 200, 48)' },  // depends on font size
+  { 'transform' : 'translate(50px)',        'result' : 'matrix(1, 0, 0, 1, 50, 0)' },
+  { 'transform' : 'translatex(-20px)',      'result' : 'matrix(1, 0, 0, 1, -20, 0)' },
+  { 'transform' : 'translateX(-20px)',      'result' : 'matrix(1, 0, 0, 1, -20, 0)' },
+  { 'transform' : 'translatey(23px)',       'result' : 'matrix(1, 0, 0, 1, 0, 23)' },
+  { 'transform' : 'translateY(-3em)',       'result' : 'matrix(1, 0, 0, 1, 0, -48)' },  // depends on font size
 
-      // translate
-      { 'transform' : 'translate(80px, 90px)',  'result' : 'matrix(1, 0, 0, 1, 80, 90)' },
-      { 'transform' : 'translate(100%, 3em)',   'result' : 'matrix(1, 0, 0, 1, 200, 48)' },  // depends on font size
-      { 'transform' : 'translate(50px)',        'result' : 'matrix(1, 0, 0, 1, 50, 0)' },
-      { 'transform' : 'translatex(-20px)',      'result' : 'matrix(1, 0, 0, 1, -20, 0)' },
-      { 'transform' : 'translateX(-20px)',      'result' : 'matrix(1, 0, 0, 1, -20, 0)' },
-      { 'transform' : 'translatey(23px)',       'result' : 'matrix(1, 0, 0, 1, 0, 23)' },
-      { 'transform' : 'translateY(-3em)',       'result' : 'matrix(1, 0, 0, 1, 0, -48)' },  // depends on font size
+  // scale
+  { 'transform' : 'scale(1.2)',             'result' : 'matrix(1.2, 0, 0, 1.2, 0, 0)' },
+  { 'transform' : 'scalex(1.5)',            'result' : 'matrix(1.5, 0, 0, 1, 0, 0)' },
+  { 'transform' : 'scaleX(1.5)',            'result' : 'matrix(1.5, 0, 0, 1, 0, 0)' },
+  { 'transform' : 'scaley(1.5)',            'result' : 'matrix(1, 0, 0, 1.5, 0, 0)' },
+  { 'transform' : 'scaleY(1.5)',            'result' : 'matrix(1, 0, 0, 1.5, 0, 0)' },
+  { 'transform' : 'scale(1.2, 0.8)',        'result' : 'matrix(1.2, 0, 0, 0.8, 0, 0)' },
+  { 'transform' : 'scale(-1.2, -0.8)',      'result' : 'matrix(-1.2, -0, -0, -0.8, 0, 0)' },
 
-      // scale
-      { 'transform' : 'scale(1.2)',             'result' : 'matrix(1.2, 0, 0, 1.2, 0, 0)' },
-      { 'transform' : 'scalex(1.5)',            'result' : 'matrix(1.5, 0, 0, 1, 0, 0)' },
-      { 'transform' : 'scaleX(1.5)',            'result' : 'matrix(1.5, 0, 0, 1, 0, 0)' },
-      { 'transform' : 'scaley(1.5)',            'result' : 'matrix(1, 0, 0, 1.5, 0, 0)' },
-      { 'transform' : 'scaleY(1.5)',            'result' : 'matrix(1, 0, 0, 1.5, 0, 0)' },
-      { 'transform' : 'scale(1.2, 0.8)',        'result' : 'matrix(1.2, 0, 0, 0.8, 0, 0)' },
-      { 'transform' : 'scale(-1.2, -0.8)',      'result' : 'matrix(-1.2, -0, -0, -0.8, 0, 0)' },
+  // skew
+  { 'transform' : 'skew(-0.7rad, 20deg)',   'result' : 'matrix(1, 0.36397, -0.842288, 1, 0, 0)' },
+  { 'transform' : 'skew(12grad)',           'result' : 'matrix(1, 0, 0.19076, 1, 0, 0)' },
+  { 'transform' : 'skewx(12grad)',          'result' : 'matrix(1, 0, 0.19076, 1, 0, 0)' },
+  { 'transform' : 'skewX(12grad)',          'result' : 'matrix(1, 0, 0.19076, 1, 0, 0)' },
+  { 'transform' : 'skewy(-12grad)',         'result' : 'matrix(1, -0.19076, 0, 1, 0, 0)' },
+  { 'transform' : 'skewY(-12grad)',         'result' : 'matrix(1, -0.19076, 0, 1, 0, 0)' },
+  { 'transform' : 'skewx(0.1turn)',         'result' : 'matrix(1, 0, 0.726543, 1, 0, 0)' },
 
-      // skew
-      { 'transform' : 'skew(-0.7rad, 20deg)',   'result' : 'matrix(1, 0.36397, -0.842288, 1, 0, 0)' },
-      { 'transform' : 'skew(12grad)',           'result' : 'matrix(1, 0, 0.19076, 1, 0, 0)' },
-      { 'transform' : 'skewx(12grad)',          'result' : 'matrix(1, 0, 0.19076, 1, 0, 0)' },
-      { 'transform' : 'skewX(12grad)',          'result' : 'matrix(1, 0, 0.19076, 1, 0, 0)' },
-      { 'transform' : 'skewy(-12grad)',         'result' : 'matrix(1, -0.19076, 0, 1, 0, 0)' },
-      { 'transform' : 'skewY(-12grad)',         'result' : 'matrix(1, -0.19076, 0, 1, 0, 0)' },
-      { 'transform' : 'skewx(0.1turn)',         'result' : 'matrix(1, 0, 0.726543, 1, 0, 0)' },
+  // rotate
+  { 'transform' : 'rotate(45deg)',          'result' : 'matrix(0.707107, 0.707107, -0.707107, 0.707107, 0, 0)' },
+  { 'transform' : 'rotate(90deg)',          'result' : 'matrix(-4.37114e-08, 1, -1, -4.37114e-08, 0, 0)' },
+  { 'transform' : 'rotate(-90deg)',         'result' : 'matrix(-4.37114e-08, -1, 1, -4.37114e-08, 0, 0)' },
+  { 'transform' : 'rotate(180deg)',         'result' : 'matrix(-1, -8.74228e-08, 8.74228e-08, -1, 0, 0)' },
+  { 'transform' : 'rotate(1.2rad)',         'result' : 'matrix(0.362358, 0.932039, -0.932039, 0.362358, 0, 0)' },
+  { 'transform' : 'rotate(0.25turn)',       'result' : 'matrix(-4.37114e-08, 1, -1, -4.37114e-08, 0, 0)' },
+  { 'transform' : 'rotate(0.5turn)',        'result' : 'matrix(-1, -8.74228e-08, 8.74228e-08, -1, 0, 0)' },
+  { 'transform' : 'rotate(1.5turn)',        'result' : 'matrix(-1, -8.74228e-08, 8.74228e-08, -1, 0, 0)' },
 
-      // rotate
-      { 'transform' : 'rotate(45deg)',          'result' : 'matrix(0.707107, 0.707107, -0.707107, 0.707107, 0, 0)' },
-      { 'transform' : 'rotate(90deg)',          'result' : 'matrix(-4.37114e-08, 1, -1, -4.37114e-08, 0, 0)' },
-      { 'transform' : 'rotate(-90deg)',         'result' : 'matrix(-4.37114e-08, -1, 1, -4.37114e-08, 0, 0)' },
-      { 'transform' : 'rotate(180deg)',         'result' : 'matrix(-1, -8.74228e-08, 8.74228e-08, -1, 0, 0)' },
-      { 'transform' : 'rotate(1.2rad)',         'result' : 'matrix(0.362358, 0.932039, -0.932039, 0.362358, 0, 0)' },
-      { 'transform' : 'rotate(0.25turn)',       'result' : 'matrix(-4.37114e-08, 1, -1, -4.37114e-08, 0, 0)' },
-      { 'transform' : 'rotate(0.5turn)',        'result' : 'matrix(-1, -8.74228e-08, 8.74228e-08, -1, 0, 0)' },
-      { 'transform' : 'rotate(1.5turn)',        'result' : 'matrix(-1, -8.74228e-08, 8.74228e-08, -1, 0, 0)' },
+  // matrix
+  { 'transform' : 'matrix(1, 0, 0, 1, 0, 0)', 'result' : 'matrix(1, 0, 0, 1, 0, 0)' },
+  { 'transform' : 'matrix(1, -0.19076, 0, 1, 0, 0)', 'result' : 'matrix(1, -0.19076, 0, 1, 0, 0)' },
+  { 'transform' : 'matrix(0.2, 0.3, 0.4, 1.1, 1.2, 1.3)', 'result' : 'matrix(0.2, 0.3, 0.4, 1.1, 1.2, 1.3)' },
 
-      // matrix
-      { 'transform' : 'matrix(1, 0, 0, 1, 0, 0)', 'result' : 'matrix(1, 0, 0, 1, 0, 0)' },
-      { 'transform' : 'matrix(1, -0.19076, 0, 1, 0, 0)', 'result' : 'matrix(1, -0.19076, 0, 1, 0, 0)' },
-      { 'transform' : 'matrix(0.2, 0.3, 0.4, 1.1, 1.2, 1.3)', 'result' : 'matrix(0.2, 0.3, 0.4, 1.1, 1.2, 1.3)' },
+  // invalid syntax
+  { 'transform' : ',rotate(12deg)', 'result' : 'none' }, // has comma
+  { 'transform' : 'rotate(12deg),', 'result' : 'none' }, // has comma
+  { 'transform' : 'rotate(12deg) +', 'result' : 'none' }, // has plus
+  { 'transform' : '(translate(50, 20))', 'result' : 'none' }, // bad syntax
+  { 'transform' : 'eggs(10)', 'result' : 'none' }, // invalid function
 
-      // invalid syntax
-      { 'transform' : ',rotate(12deg)', 'result' : 'none' }, // has comma
-      { 'transform' : 'rotate(12deg),', 'result' : 'none' }, // has comma
-      { 'transform' : 'rotate(12deg) +', 'result' : 'none' }, // has plus
-      { 'transform' : '(translate(50, 20))', 'result' : 'none' }, // bad syntax
-      { 'transform' : 'eggs(10)', 'result' : 'none' }, // invalid function
+  // invalid translate
+  { 'transform' : 'translate(50, 20)', 'result' : 'none' }, // missing units
+  { 'transform' : 'translate()', 'result' : 'none' }, // no arguments
+  { 'transform' : 'translate(10px, 20px, 30px)', 'result' : 'none' }, // too many arguments
+  { 'transform' : 'translate(10px, 20px, 30px, 40px)', 'result' : 'none' }, // too many arguments
+  { 'transform' : 'translate(10smidgens)', 'result' : 'none' }, // invalid units
+  { 'transform' : 'translate(10px, 10smidgens)', 'result' : 'none' }, // invalid units
+  { 'transform' : 'translateX(10px, 20px)', 'result' : 'none' }, // too many arguments
+  { 'transform' : 'translateX(10px, 20px, 30px)', 'result' : 'none' }, // too many arguments
+  { 'transform' : 'translateX(10smidgens)', 'result' : 'none' }, // invalid units
+  { 'transform' : 'translateX(10px, 10smidgens)', 'result' : 'none' }, // invalid units
+  { 'transform' : 'translateY(10px, 20px)', 'result' : 'none' }, // too many arguments
+  { 'transform' : 'translateY(10px, 20px, 30px)', 'result' : 'none' }, // too many arguments
+  { 'transform' : 'translateY(10smidgens)', 'result' : 'none' }, // invalid units
+  { 'transform' : 'translateY(10px, 10smidgens)', 'result' : 'none' }, // invalid units
 
-      // invalid translate
-      { 'transform' : 'translate(50, 20)', 'result' : 'none' }, // missing units
-      { 'transform' : 'translate()', 'result' : 'none' }, // no arguments
-      { 'transform' : 'translate(10px, 20px, 30px)', 'result' : 'none' }, // too many arguments
-      { 'transform' : 'translate(10px, 20px, 30px, 40px)', 'result' : 'none' }, // too many arguments
-      { 'transform' : 'translate(10smidgens)', 'result' : 'none' }, // invalid units
-      { 'transform' : 'translate(10px, 10smidgens)', 'result' : 'none' }, // invalid units
-      { 'transform' : 'translateX(10px, 20px)', 'result' : 'none' }, // too many arguments
-      { 'transform' : 'translateX(10px, 20px, 30px)', 'result' : 'none' }, // too many arguments
-      { 'transform' : 'translateX(10smidgens)', 'result' : 'none' }, // invalid units
-      { 'transform' : 'translateX(10px, 10smidgens)', 'result' : 'none' }, // invalid units
-      { 'transform' : 'translateY(10px, 20px)', 'result' : 'none' }, // too many arguments
-      { 'transform' : 'translateY(10px, 20px, 30px)', 'result' : 'none' }, // too many arguments
-      { 'transform' : 'translateY(10smidgens)', 'result' : 'none' }, // invalid units
-      { 'transform' : 'translateY(10px, 10smidgens)', 'result' : 'none' }, // invalid units
+  // invalid scale
+  { 'transform' : 'scale(2px, 2px)', 'result' : 'none' }, // has units
+  { 'transform' : 'scale(2, 2px)', 'result' : 'none' }, // has units
+  { 'transform' : 'scale()', 'result' : 'none' }, // no arguments
+  { 'transform' : 'scale(1, 2, 3)', 'result' : 'none' }, // too many arguments
+  { 'transform' : 'scale(2smidgens)', 'result' : 'none' }, // invalid units
+  { 'transform' : 'scale(2, 2smidgens)', 'result' : 'none' }, // invalid units
 
-      // invalid scale
-      { 'transform' : 'scale(2px, 2px)', 'result' : 'none' }, // has units
-      { 'transform' : 'scale(2, 2px)', 'result' : 'none' }, // has units
-      { 'transform' : 'scale()', 'result' : 'none' }, // no arguments
-      { 'transform' : 'scale(1, 2, 3)', 'result' : 'none' }, // too many arguments
-      { 'transform' : 'scale(2smidgens)', 'result' : 'none' }, // invalid units
-      { 'transform' : 'scale(2, 2smidgens)', 'result' : 'none' }, // invalid units
+  // invalid rotate
+  { 'transform' : 'rotate(10)', 'result' : 'none' }, // no units
+  { 'transform' : 'rotate()', 'result' : 'none' }, // no arguments
+  { 'transform' : 'rotate(10deg, 20deg)', 'result' : 'none' }, // too many arguments
+  { 'transform' : 'rotate(2turns)', 'result' : 'none' }, // invalid units -- 'turn' not 'turns'
+  { 'transform' : 'rotate(2spins)', 'result' : 'none' }, // invalid units
+  { 'transform' : 'rotate(2, 2spins)', 'result' : 'none' }, // invalid units
 
-      // invalid rotate
-      { 'transform' : 'rotate(10)', 'result' : 'none' }, // no units
-      { 'transform' : 'rotate()', 'result' : 'none' }, // no arguments
-      { 'transform' : 'rotate(10deg, 20deg)', 'result' : 'none' }, // too many arguments
-      { 'transform' : 'rotate(2turns)', 'result' : 'none' }, // invalid units -- 'turn' not 'turns'
-      { 'transform' : 'rotate(2spins)', 'result' : 'none' }, // invalid units
-      { 'transform' : 'rotate(2, 2spins)', 'result' : 'none' }, // invalid units
+  // invalid skew
+  { 'transform' : 'skew(10)', 'result' : 'none' }, // no units
+  { 'transform' : 'skew()', 'result' : 'none' }, // no arguments
+  { 'transform' : 'skew(10deg, 20deg, 30deg)', 'result' : 'none' }, // too many arguments
+  { 'transform' : 'skew(2bits)', 'result' : 'none' }, // invalid units
+  { 'transform' : 'skew(2, 2bits)', 'result' : 'none' }, // invalid units
+  { 'transform' : 'skewX(10)', 'result' : 'none' }, // no units
+  { 'transform' : 'skewX()', 'result' : 'none' }, // no arguments
+  { 'transform' : 'skewX(10deg, 20deg)', 'result' : 'none' }, // too many arguments
+  { 'transform' : 'skewX(2bits)', 'result' : 'none' }, // invalid units
+  { 'transform' : 'skewY(10)', 'result' : 'none' }, // no units
+  { 'transform' : 'skewY()', 'result' : 'none' }, // no arguments
+  { 'transform' : 'skewY(10deg, 20deg)', 'result' : 'none' }, // too many arguments
+  { 'transform' : 'skewY(2bits)', 'result' : 'none' }, // invalid units
 
-      // invalid skew
-      { 'transform' : 'skew(10)', 'result' : 'none' }, // no units
-      { 'transform' : 'skew()', 'result' : 'none' }, // no arguments
-      { 'transform' : 'skew(10deg, 20deg, 30deg)', 'result' : 'none' }, // too many arguments
-      { 'transform' : 'skew(2bits)', 'result' : 'none' }, // invalid units
-      { 'transform' : 'skew(2, 2bits)', 'result' : 'none' }, // invalid units
-      { 'transform' : 'skewX(10)', 'result' : 'none' }, // no units
-      { 'transform' : 'skewX()', 'result' : 'none' }, // no arguments
-      { 'transform' : 'skewX(10deg, 20deg)', 'result' : 'none' }, // too many arguments
-      { 'transform' : 'skewX(2bits)', 'result' : 'none' }, // invalid units
-      { 'transform' : 'skewY(10)', 'result' : 'none' }, // no units
-      { 'transform' : 'skewY()', 'result' : 'none' }, // no arguments
-      { 'transform' : 'skewY(10deg, 20deg)', 'result' : 'none' }, // too many arguments
-      { 'transform' : 'skewY(2bits)', 'result' : 'none' }, // invalid units
+  // invalid matrix
+  { 'transform' : 'matrix()', 'result' : 'none' }, // no arguments
+  { 'transform' : 'matrix(2, 0, 0, 2)', 'result' : 'none' }, // not enough arguments
+  { 'transform' : 'matrix(0.978148, 0.207912, -0.207912, 0.978148, 50, 20, 666)', 'result' : 'none' }, // too many arguments
+  { 'transform' : 'matrix(1, 0, 0, 1, 20px, 50px)', 'result' : 'none' } // has units
+];
 
-      // invalid matrix
-      { 'transform' : 'matrix()', 'result' : 'none' }, // no arguments
-      { 'transform' : 'matrix(2, 0, 0, 2)', 'result' : 'none' }, // not enough arguments
-      { 'transform' : 'matrix(0.978148, 0.207912, -0.207912, 0.978148, 50, 20, 666)', 'result' : 'none' }, // too many arguments
-      { 'transform' : 'matrix(1, 0, 0, 1, 20px, 50px)', 'result' : 'none' } // has units
-      
-    ];
-    
-    function runTests()
-    {
-      testTransforms();
+gTests.forEach((curTest) => {
+  test(() => {
+    var testBox = document.getElementById('test-box');
 
-      if (window.testRunner)
-        testRunner.notifyDone();
-    }
-  </script>
-</head>
-<body onload="runTests()">
+    // Reset the transform just in case the next step fails
+    testBox.style.webkitTransform = 'none';
+    testBox.style.webkitTransform = curTest.transform;
 
-  <div class="container">
-    <div id="test-box" class="box"></div>
-  </div>
+    var computedTransform = getComputedStyle(testBox).webkitTransform;
 
-  <div id="results">
-  </div>
-</body>
-</html>
+    assert_true(compareMatrices(computedTransform, curTest.result));
+  }, `Computed value of ${curTest.transform}`);
+});
+
+</script>
diff --git a/third_party/blink/web_tests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/border-radius-composited-subframe-expected.png b/third_party/blink/web_tests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/border-radius-composited-subframe-expected.png
index 0734fb1..6b63616 100644
--- a/third_party/blink/web_tests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/border-radius-composited-subframe-expected.png
+++ b/third_party/blink/web_tests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/border-radius-composited-subframe-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/subresource-web-bundles/README.md b/third_party/blink/web_tests/virtual/subresource-web-bundles/README.md
new file mode 100644
index 0000000..3b5ab6f
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/subresource-web-bundles/README.md
@@ -0,0 +1 @@
+This directory is for testing the SubresourceWebBundles feature.
diff --git a/third_party/blink/web_tests/virtual/subresource-web-bundles/external/wpt/web-bundle/subresoruce-loading/README.txt b/third_party/blink/web_tests/virtual/subresource-web-bundles/external/wpt/web-bundle/subresoruce-loading/README.txt
new file mode 100644
index 0000000..3b5ab6f
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/subresource-web-bundles/external/wpt/web-bundle/subresoruce-loading/README.txt
@@ -0,0 +1 @@
+This directory is for testing the SubresourceWebBundles feature.
diff --git a/third_party/blink/web_tests/virtual/wbn-from-network/external/wpt/web-bundle/README.txt b/third_party/blink/web_tests/virtual/wbn-from-network/external/wpt/web-bundle/wbn-from-network/README.txt
similarity index 100%
rename from third_party/blink/web_tests/virtual/wbn-from-network/external/wpt/web-bundle/README.txt
rename to third_party/blink/web_tests/virtual/wbn-from-network/external/wpt/web-bundle/wbn-from-network/README.txt
diff --git a/third_party/blink/web_tests/virtual/web-components-v0-disabled/fast/dom/shadow/input-color-in-content-expected.txt b/third_party/blink/web_tests/virtual/web-components-v0-disabled/fast/dom/shadow/input-color-in-content-expected.txt
deleted file mode 100644
index 70fa6dbe..0000000
--- a/third_party/blink/web_tests/virtual/web-components-v0-disabled/fast/dom/shadow/input-color-in-content-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-CONSOLE ERROR: line 13: Uncaught TypeError: host.createShadowRoot is not a function
-FAIL successfullyParsed should be true. Was false.
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt
deleted file mode 100644
index 09790d3..0000000
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-This is a testharness.js-based test.
-PASS getStats() with no argument should succeed
-PASS getStats(null) should succeed
-PASS getStats() with track not added to connection should reject with InvalidAccessError
-PASS getStats() with track added via addTrack should succeed
-FAIL getStats() with track added via addTransceiver should succeed promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
-FAIL getStats() with track associated with more than one sender should reject with InvalidAccessError promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
-FAIL getStats() with track associated with both sender and receiver should reject with InvalidAccessError Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'.
-PASS getStats() with no argument should return stats report containing peer-connection stats on an empty PC
-FAIL getStats() with no argument should return stats report containing peer-connection stats and outbound-track-stats assert_true: Expect statsReport to contain stats object of type outbound-rtp expected true got false
-FAIL getStats() with no argument should return stats for no-stream tracks assert_true: Expect statsReport to contain stats object of type outbound-rtp expected true got false
-FAIL getStats() on track associated with RtpSender should return stats report containing outbound-rtp stats assert_equals: Expect dictionary.remoteId to be string expected "string" but got "undefined"
-FAIL getStats() on track associated with RtpReceiver should return stats report containing inbound-rtp stats assert_equals: Expect dictionary.codecId to be string expected "string" but got "undefined"
-FAIL getStats() with connected peer connections having tracks and data channel should return all mandatory to implement stats assert_unreached: test failed with error: Error: assert_true: Expect dictionary.dataChannelIdentifier to be integer expected true got false Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt
deleted file mode 100644
index 9aacd7bb1..0000000
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-FAIL receiver.getStats() via addTransceiver should return stats report containing inbound-rtp stats promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
-FAIL receiver.getStats() via addTrack should return stats report containing inbound-rtp stats assert_equals: Expect dictionary.codecId to be string expected "string" but got "undefined"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCRtpSender-getStats.https-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCRtpSender-getStats.https-expected.txt
deleted file mode 100644
index f0d433ae..0000000
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCRtpSender-getStats.https-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-FAIL sender.getStats() via addTransceiver should return stats report containing outbound-rtp stats promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
-FAIL sender.getStats() via addTrack should return stats report containing outbound-rtp stats assert_equals: Expect dictionary.remoteId to be string expected "string" but got "undefined"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/protocol/crypto-suite.https-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/protocol/crypto-suite.https-expected.txt
deleted file mode 100644
index 682f695..0000000
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/protocol/crypto-suite.https-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-This is a testharness.js-based test.
-FAIL tlsVersion is acceptable on data-only promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'transport' of null"
-FAIL tlsVersion is acceptable on video-only promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
-FAIL dtlsCipher is acceptable on data-only promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'transport' of null"
-FAIL dtlsCipher is acceptable on video-only promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
-FAIL srtpCipher is acceptable on data-only promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'transport' of null"
-FAIL srtpCipher is acceptable on video-only promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
-FAIL tlsGroup is acceptable on data-only promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'transport' of null"
-FAIL tlsGroup is acceptable on video-only promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/shadow-dom/css-cascade-upgrade-from-another-tree.html b/third_party/blink/web_tests/web-components-v0-only/css-cascade-upgrade-from-another-tree.html
similarity index 100%
rename from third_party/blink/web_tests/shadow-dom/css-cascade-upgrade-from-another-tree.html
rename to third_party/blink/web_tests/web-components-v0-only/css-cascade-upgrade-from-another-tree.html
diff --git a/third_party/blink/web_tests/shadow-dom/css-cascade-upgrade-from-v0-to-v1.html b/third_party/blink/web_tests/web-components-v0-only/css-cascade-upgrade-from-v0-to-v1.html
similarity index 100%
rename from third_party/blink/web_tests/shadow-dom/css-cascade-upgrade-from-v0-to-v1.html
rename to third_party/blink/web_tests/web-components-v0-only/css-cascade-upgrade-from-v0-to-v1.html
diff --git a/third_party/blink/web_tests/fast/css/remove-pending-sheet-html-import-crash-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/css/remove-pending-sheet-html-import-crash-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/css/remove-pending-sheet-html-import-crash-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/css/remove-pending-sheet-html-import-crash-expected.txt
diff --git a/third_party/blink/web_tests/fast/css/remove-pending-sheet-html-import-crash.html b/third_party/blink/web_tests/web-components-v0-only/fast/css/remove-pending-sheet-html-import-crash.html
similarity index 100%
rename from third_party/blink/web_tests/fast/css/remove-pending-sheet-html-import-crash.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/css/remove-pending-sheet-html-import-crash.html
diff --git a/third_party/blink/web_tests/fast/css/resources/import-layout-with-pending-sheet.html b/third_party/blink/web_tests/web-components-v0-only/fast/css/resources/import-layout-with-pending-sheet.html
similarity index 100%
rename from third_party/blink/web_tests/fast/css/resources/import-layout-with-pending-sheet.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/css/resources/import-layout-with-pending-sheet.html
diff --git a/third_party/blink/web_tests/fast/dom/HTMLTemplateElement/import-template-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-HTMLTemplateElement/import-template-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/HTMLTemplateElement/import-template-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-HTMLTemplateElement/import-template-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/HTMLTemplateElement/import-template.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-HTMLTemplateElement/import-template.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/HTMLTemplateElement/import-template.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-HTMLTemplateElement/import-template.html
diff --git a/third_party/blink/web_tests/fast/dom/HTMLTemplateElement/ownerDocument-import-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-HTMLTemplateElement/ownerDocument-import-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/HTMLTemplateElement/ownerDocument-import-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-HTMLTemplateElement/ownerDocument-import-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/HTMLTemplateElement/ownerDocument-import.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-HTMLTemplateElement/ownerDocument-import.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/HTMLTemplateElement/ownerDocument-import.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-HTMLTemplateElement/ownerDocument-import.html
diff --git a/third_party/blink/web_tests/fast/dom/HTMLTemplateElement/resources/template-import.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-HTMLTemplateElement/resources/template-import.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/HTMLTemplateElement/resources/template-import.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-HTMLTemplateElement/resources/template-import.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/adopt-node-with-shadow-root-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/adopt-node-with-shadow-root-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/adopt-node-with-shadow-root-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/adopt-node-with-shadow-root-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/adopt-node-with-shadow-root.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/adopt-node-with-shadow-root.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/adopt-node-with-shadow-root.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/adopt-node-with-shadow-root.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/anchor-content-projected-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/anchor-content-projected-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/anchor-content-projected-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/anchor-content-projected-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/anchor-content-projected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/anchor-content-projected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/anchor-content-projected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/anchor-content-projected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-after-style-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-after-style-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-after-style-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-after-style-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-after-style-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-after-style-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-after-style-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-after-style-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-after-style.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-after-style.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-after-style.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-after-style.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-child-whitespace-between-span-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-child-whitespace-between-span-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-child-whitespace-between-span-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-child-whitespace-between-span-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-child-whitespace-between-span.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-child-whitespace-between-span.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-child-whitespace-between-span.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-child-whitespace-between-span.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-complex-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-complex-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-complex-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-complex-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-complex-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-complex-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-complex-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-complex-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-complex.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-complex.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-complex.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-complex.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-dynamic-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-dynamic-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-dynamic-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-dynamic-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-dynamic-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-dynamic-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-dynamic-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-dynamic-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-dynamic.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-dynamic.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-dynamic.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-dynamic.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-fallback-crash-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-fallback-crash-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-fallback-crash-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-fallback-crash-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-fallback-crash.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-fallback-crash.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-fallback-crash.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-fallback-crash.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-fallback-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-fallback-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-fallback-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-fallback-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-fallback-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-fallback-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-fallback-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-fallback-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-fallback-reprojection-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-fallback-reprojection-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-fallback-reprojection-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-fallback-reprojection-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-fallback-reprojection-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-fallback-reprojection-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-fallback-reprojection-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-fallback-reprojection-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-fallback-reprojection.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-fallback-reprojection.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-fallback-reprojection.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-fallback-reprojection.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-fallback.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-fallback.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-fallback.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-fallback.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-reattach-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-reattach-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-reattach-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-reattach-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-reattach-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-reattach-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-reattach-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-reattach-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-reattach.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-reattach.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-reattach.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-reattach.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-recalc-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-recalc-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-recalc-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-recalc-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-recalc.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-recalc.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-recalc.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-recalc.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-shadow-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-shadow-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-shadow-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-shadow-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-shadow-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-shadow-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-shadow-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-shadow-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-reprojection-shadow.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-shadow.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-reprojection-shadow.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-reprojection-shadow.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-selector-query.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-selector-query.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-selector-query.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-selector-query.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-text-selection-crash.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-text-selection-crash.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-text-selection-crash.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-text-selection-crash.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-whitespace-attach-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-whitespace-attach-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-whitespace-attach-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-whitespace-attach-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-whitespace-attach-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-whitespace-attach-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-whitespace-attach-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-whitespace-attach-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/content-whitespace-attach.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-whitespace-attach.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/content-whitespace-attach.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/content-whitespace-attach.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/create-content-element-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/create-content-element-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/create-content-element-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/create-content-element-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/create-content-element.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/create-content-element.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/create-content-element.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/create-content-element.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/distribution-attribute-modified-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-attribute-modified-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/distribution-attribute-modified-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-attribute-modified-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/distribution-attribute-modified-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-attribute-modified-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/distribution-attribute-modified-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-attribute-modified-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/distribution-attribute-modified.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-attribute-modified.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/distribution-attribute-modified.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-attribute-modified.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/distribution-className-modified-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-className-modified-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/distribution-className-modified-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-className-modified-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/distribution-className-modified-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-className-modified-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/distribution-className-modified-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-className-modified-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/distribution-className-modified.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-className-modified.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/distribution-className-modified.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-className-modified.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/distribution-for-detached-subtree-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-for-detached-subtree-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/distribution-for-detached-subtree-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-for-detached-subtree-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/distribution-for-detached-subtree.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-for-detached-subtree.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/distribution-for-detached-subtree.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-for-detached-subtree.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/distribution-for-event-path-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-for-event-path-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/distribution-for-event-path-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-for-event-path-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/distribution-for-event-path.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-for-event-path.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/distribution-for-event-path.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-for-event-path.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/distribution-id-modified-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-id-modified-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/distribution-id-modified-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-id-modified-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/distribution-id-modified-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-id-modified-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/distribution-id-modified-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-id-modified-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/distribution-id-modified.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-id-modified.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/distribution-id-modified.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-id-modified.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/distribution-update-recalcs-style-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-update-recalcs-style-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/distribution-update-recalcs-style-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-update-recalcs-style-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/distribution-update-recalcs-style.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-update-recalcs-style.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/distribution-update-recalcs-style.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/distribution-update-recalcs-style.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/img-display-contents-crash-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/img-display-contents-crash-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/img-display-contents-crash-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/img-display-contents-crash-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/img-display-contents-crash.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/img-display-contents-crash.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/img-display-contents-crash.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/img-display-contents-crash.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/input-date-display-contents-crash-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/input-date-display-contents-crash-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/input-date-display-contents-crash-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/input-date-display-contents-crash-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/input-date-display-contents-crash.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/input-date-display-contents-crash.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/input-date-display-contents-crash.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/input-date-display-contents-crash.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/no-style-sharing-with-uncommon-attribute-and-pseudo-content-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/no-style-sharing-with-uncommon-attribute-and-pseudo-content-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/no-style-sharing-with-uncommon-attribute-and-pseudo-content-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/no-style-sharing-with-uncommon-attribute-and-pseudo-content-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/no-style-sharing-with-uncommon-attribute-and-pseudo-content-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/no-style-sharing-with-uncommon-attribute-and-pseudo-content-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/no-style-sharing-with-uncommon-attribute-and-pseudo-content-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/no-style-sharing-with-uncommon-attribute-and-pseudo-content-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/no-style-sharing-with-uncommon-attribute-and-pseudo-content.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/no-style-sharing-with-uncommon-attribute-and-pseudo-content.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/no-style-sharing-with-uncommon-attribute-and-pseudo-content.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/no-style-sharing-with-uncommon-attribute-and-pseudo-content.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/reattach-content-ancestor-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reattach-content-ancestor-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/reattach-content-ancestor-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reattach-content-ancestor-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/reattach-content-ancestor-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reattach-content-ancestor-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/reattach-content-ancestor-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reattach-content-ancestor-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/reattach-content-ancestor.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reattach-content-ancestor.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/reattach-content-ancestor.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reattach-content-ancestor.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/reprojection-attribute-modified-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-attribute-modified-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/reprojection-attribute-modified-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-attribute-modified-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/reprojection-attribute-modified-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-attribute-modified-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/reprojection-attribute-modified-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-attribute-modified-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/reprojection-attribute-modified.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-attribute-modified.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/reprojection-attribute-modified.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-attribute-modified.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/reprojection-className-modified-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-className-modified-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/reprojection-className-modified-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-className-modified-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/reprojection-className-modified-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-className-modified-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/reprojection-className-modified-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-className-modified-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/reprojection-className-modified.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-className-modified.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/reprojection-className-modified.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-className-modified.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/reprojection-id-modified-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-id-modified-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/reprojection-id-modified-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-id-modified-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/reprojection-id-modified-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-id-modified-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/reprojection-id-modified-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-id-modified-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/reprojection-id-modified.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-id-modified.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/reprojection-id-modified.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/reprojection-id-modified.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/resources/svg_placeholder.svg b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/resources/svg_placeholder.svg
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/resources/svg_placeholder.svg
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/resources/svg_placeholder.svg
diff --git a/third_party/blink/web_tests/fast/dom/shadow/shadow-content-crash-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-content-crash-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/shadow-content-crash-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-content-crash-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/shadow-content-crash.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-content-crash.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/shadow-content-crash.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-content-crash.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/shadow-contents-event-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-event-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/shadow-contents-event-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-event-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/shadow-contents-event.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-event.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/shadow-contents-event.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-event.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/shadow-contents-fallback-dynamic-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-fallback-dynamic-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/shadow-contents-fallback-dynamic-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-fallback-dynamic-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/shadow-contents-fallback-dynamic.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-fallback-dynamic.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/shadow-contents-fallback-dynamic.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-fallback-dynamic.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/shadow-contents-fallback-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-fallback-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/shadow-contents-fallback-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-fallback-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/shadow-contents-fallback.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-fallback.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/shadow-contents-fallback.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-fallback.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/shadow-contents-select-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-select-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/shadow-contents-select-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-select-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/shadow-contents-select-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-select-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/shadow-contents-select-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-select-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/shadow-contents-select.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-select.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/shadow-contents-select.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-contents-select.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/shadow-disable-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-disable-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/shadow-disable-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-disable-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/shadow-disable.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-disable.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/shadow-disable.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/shadow-disable.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/style-sharing-with-content-and-host-expected.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/style-sharing-with-content-and-host-expected.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/style-sharing-with-content-and-host-expected.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/style-sharing-with-content-and-host-expected.html
diff --git a/third_party/blink/web_tests/fast/dom/shadow/style-sharing-with-content-and-host-expected.txt b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/style-sharing-with-content-and-host-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/style-sharing-with-content-and-host-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/style-sharing-with-content-and-host-expected.txt
diff --git a/third_party/blink/web_tests/fast/dom/shadow/style-sharing-with-content-and-host.html b/third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/style-sharing-with-content-and-host.html
similarity index 100%
rename from third_party/blink/web_tests/fast/dom/shadow/style-sharing-with-content-and-host.html
rename to third_party/blink/web_tests/web-components-v0-only/fast/dom-shadow/style-sharing-with-content-and-host.html
diff --git a/third_party/blink/web_tests/shadow-dom/slotted-pseudo-element-in-v0-tree-crash-expected.txt b/third_party/blink/web_tests/web-components-v0-only/slotted-pseudo-element-in-v0-tree-crash-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/shadow-dom/slotted-pseudo-element-in-v0-tree-crash-expected.txt
rename to third_party/blink/web_tests/web-components-v0-only/slotted-pseudo-element-in-v0-tree-crash-expected.txt
diff --git a/third_party/blink/web_tests/shadow-dom/slotted-pseudo-element-in-v0-tree-crash.html b/third_party/blink/web_tests/web-components-v0-only/slotted-pseudo-element-in-v0-tree-crash.html
similarity index 100%
rename from third_party/blink/web_tests/shadow-dom/slotted-pseudo-element-in-v0-tree-crash.html
rename to third_party/blink/web_tests/web-components-v0-only/slotted-pseudo-element-in-v0-tree-crash.html
diff --git a/third_party/blink/web_tests/svg/foreignObject/shadow-dom-v0-crash.html b/third_party/blink/web_tests/web-components-v0-only/svg-foreignObject/shadow-dom-v0-crash.html
similarity index 100%
rename from third_party/blink/web_tests/svg/foreignObject/shadow-dom-v0-crash.html
rename to third_party/blink/web_tests/web-components-v0-only/svg-foreignObject/shadow-dom-v0-crash.html
diff --git a/third_party/blink/web_tests/webcodecs/videoframe-imagebitmap.html b/third_party/blink/web_tests/webcodecs/videoframe-imagebitmap.html
new file mode 100644
index 0000000..b23e0755
--- /dev/null
+++ b/third_party/blink/web_tests/webcodecs/videoframe-imagebitmap.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+  'use strict';
+  function testCanvas_0f0(ctx, assert_compares) {
+    let colorData = ctx.getImageData(50, 50, 1, 1).data;
+    assert_compares(colorData[0], 0);
+    assert_compares(colorData[1], 255);
+    assert_compares(colorData[2], 0);
+    assert_compares(colorData[3], 255);
+  }
+
+  promise_test(() => {
+    let canvas = document.createElement('canvas');
+    canvas.width = canvas.height = 100;
+    let ctx = canvas.getContext('2d');
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, 100, 100);
+    testCanvas_0f0(ctx, assert_equals);
+
+    return createImageBitmap(canvas).then((fromImageBitmap) => {
+      let videoFrame = new VideoFrame({ timestamp: 0 }, fromImageBitmap);
+      videoFrame.createImageBitmap().then((toImageBitmap) => {
+        let myCanvas = document.createElement('canvas');
+        myCanvas.width = myCanvas.height = 100;
+        let myCtx = myCanvas.getContext('2d');
+        myCtx.drawImage(toImageBitmap, 0, 0);
+        testCanvas_0f0(myCtx, (actual, expected) => {
+          assert_approx_equals(actual, expected, 1);
+        });
+      });
+    });
+  }, 'Test should not return any error');
+
+</script>
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 2f7560bc..b19e92d1 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -8797,6 +8797,7 @@
     getter visibleHeight
     getter visibleWidth
     method constructor
+    method createImageBitmap
     method release
 interface VideoPlaybackQuality
     attribute @@toStringTag
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index 21e2033d..3077037 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: unknown
-Revision: c7d1d2a1dd7cf2442cbb8aa8da7348fa01d54182
+Revision: 7a70b0f1513d2787437aafc6593c97cbd0f2d94e
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_win.cc b/third_party/crashpad/crashpad/client/crashpad_client_win.cc
index 4963f24..e1bdf72c 100644
--- a/third_party/crashpad/crashpad/client/crashpad_client_win.cc
+++ b/third_party/crashpad/crashpad/client/crashpad_client_win.cc
@@ -274,8 +274,13 @@
 //! \param[out] pipe_handle The first pipe instance corresponding for the pipe.
 void CreatePipe(std::wstring* pipe_name, ScopedFileHANDLE* pipe_instance) {
   int tries = 5;
-  std::string pipe_name_base =
-      base::StringPrintf("\\\\.\\pipe\\crashpad_%lu_", GetCurrentProcessId());
+  std::string pipe_name_base = base::StringPrintf(
+#if defined(WINDOWS_UWP)
+      "\\\\.\\pipe\\LOCAL\\crashpad_%lu_",
+#else
+      "\\\\.\\pipe\\crashpad_%lu_",
+#endif
+      GetCurrentProcessId());
   do {
     *pipe_name = base::UTF8ToUTF16(pipe_name_base + RandomString());
 
diff --git a/third_party/crashpad/crashpad/client/simple_address_range_bag.h b/third_party/crashpad/crashpad/client/simple_address_range_bag.h
index c69fa5a..d288303 100644
--- a/third_party/crashpad/crashpad/client/simple_address_range_bag.h
+++ b/third_party/crashpad/crashpad/client/simple_address_range_bag.h
@@ -16,6 +16,7 @@
 #define CRASHPAD_CLIENT_SIMPLE_ADDRESS_RANGE_BAG_H_
 
 #include <stdint.h>
+#include <string.h>
 
 #include <type_traits>
 
diff --git a/third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc b/third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc
index 7f6d7c7e..1f361ac 100644
--- a/third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc
+++ b/third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc
@@ -589,6 +589,14 @@
     return false;
   }
 
+  // GNU ld.so doesn't adjust the vdso's dynamic array entries by the load bias.
+  // If the address is too small to point into the loaded module range and is
+  // small enough to be an offset from the base of the module, adjust it now.
+  if (string_table_address < memory_.Base() &&
+      string_table_address < memory_.Size()) {
+    string_table_address += GetLoadBias();
+  }
+
   if (!memory_.ReadCStringSizeLimited(
           string_table_address + offset, string_table_size - offset, string)) {
     LOG(ERROR) << "missing nul-terminator";
diff --git a/third_party/crashpad/crashpad/snapshot/linux/debug_rendezvous.cc b/third_party/crashpad/crashpad/snapshot/linux/debug_rendezvous.cc
index e27768d..42384f7 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/debug_rendezvous.cc
+++ b/third_party/crashpad/crashpad/snapshot/linux/debug_rendezvous.cc
@@ -19,6 +19,11 @@
 #include <set>
 
 #include "base/logging.h"
+#include "build/build_config.h"
+
+#if defined(OS_ANDROID)
+#include <android/api-level.h>
+#endif
 
 namespace crashpad {
 
@@ -137,6 +142,17 @@
     modules_.push_back(entry);
   }
 
+#if defined(OS_ANDROID)
+  // Android P (API 28) mistakenly places the vdso in the first entry in the
+  // link map.
+  const int android_runtime_api = android_get_device_api_level();
+  if (android_runtime_api == 28 && executable_.name == "[vdso]") {
+    LinkEntry executable = modules_[0];
+    modules_[0] = executable_;
+    executable_ = executable;
+  }
+#endif  // OS_ANDROID
+
   return true;
 }
 
diff --git a/third_party/crashpad/crashpad/snapshot/linux/debug_rendezvous_test.cc b/third_party/crashpad/crashpad/snapshot/linux/debug_rendezvous_test.cc
index be22c90..71a0a7b 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/debug_rendezvous_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/linux/debug_rendezvous_test.cc
@@ -74,6 +74,13 @@
   LinuxVMAddress debug_address;
   ASSERT_TRUE(exe_reader.GetDebugAddress(&debug_address));
 
+  VMAddress exe_dynamic_address = 0;
+  if (exe_reader.GetDynamicArrayAddress(&exe_dynamic_address)) {
+    CheckedLinuxAddressRange exe_range(
+        connection->Is64Bit(), exe_reader.Address(), exe_reader.Size());
+    EXPECT_TRUE(exe_range.ContainsValue(exe_dynamic_address));
+  }
+
   // start the actual tests
   DebugRendezvous debug;
   ASSERT_TRUE(debug.Initialize(range, debug_address));
@@ -85,8 +92,13 @@
   EXPECT_NE(debug.Executable()->name.find("crashpad_snapshot_test"),
             std::string::npos);
 
-  // Android's loader never sets the dynamic array for the executable.
-  EXPECT_EQ(debug.Executable()->dynamic_array, 0u);
+  // Android's loader doesn't set the dynamic array for the executable in the
+  // link map until Android 10.0 (API 29).
+  if (android_runtime_api >= 29) {
+    EXPECT_EQ(debug.Executable()->dynamic_array, exe_dynamic_address);
+  } else {
+    EXPECT_EQ(debug.Executable()->dynamic_array, 0u);
+  }
 #else
   // glibc's loader implements most of the tested features that Android's was
   // missing but has since gained.
@@ -94,9 +106,7 @@
 
   // glibc's loader does not set the name for the executable.
   EXPECT_TRUE(debug.Executable()->name.empty());
-  CheckedLinuxAddressRange exe_range(
-      connection->Is64Bit(), exe_reader.Address(), exe_reader.Size());
-  EXPECT_TRUE(exe_range.ContainsValue(debug.Executable()->dynamic_array));
+  EXPECT_EQ(debug.Executable()->dynamic_array, exe_dynamic_address);
 #endif  // OS_ANDROID
 
   // Android's loader doesn't set the load bias until Android 4.3 (API 18).
@@ -137,7 +147,8 @@
     while ((mapping = possible_mappings->Next())) {
       auto parsed_module = std::make_unique<ElfImageReader>();
       VMAddress dynamic_address;
-      if (parsed_module->Initialize(range, mapping->range.Base()) &&
+      if (parsed_module->Initialize(
+              range, mapping->range.Base(), possible_mappings->Count() == 0) &&
           parsed_module->GetDynamicArrayAddress(&dynamic_address) &&
           dynamic_address == module.dynamic_array) {
         module_reader = std::move(parsed_module);
diff --git a/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc b/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc
index b96abfe..ee246e8 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc
+++ b/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc
@@ -439,7 +439,7 @@
       if (parsed_exe->Initialize(
               range,
               mapping->range.Base(),
-              /* verbose= */ possible_mappings->Count() == 1) &&
+              /* verbose= */ possible_mappings->Count() == 0) &&
           parsed_exe->GetProgramHeaderTableAddress() == phdrs) {
         exe_mapping = mapping;
         exe_reader = std::move(parsed_exe);
@@ -508,7 +508,7 @@
         if (parsed_module->Initialize(
                 range,
                 mapping->range.Base(),
-                /* verbose= */ possible_mappings->Count() == 1) &&
+                /* verbose= */ possible_mappings->Count() == 0) &&
             parsed_module->GetDynamicArrayAddress(&dynamic_address) &&
             dynamic_address == entry.dynamic_array) {
           module_mapping = mapping;
diff --git a/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux_test.cc b/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux_test.cc
index 5b57236..73e350db 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux_test.cc
@@ -491,23 +491,29 @@
   auto modules =
       reinterpret_cast<const std::vector<ProcessReaderLinux::Module>*>(data);
 
-  auto phdr_addr = FromPointerCast<LinuxVMAddress>(info->dlpi_phdr);
 
 #if defined(OS_ANDROID)
-  // Bionic includes a null entry.
-  if (!phdr_addr) {
-    EXPECT_EQ(info->dlpi_name, nullptr);
+  // Prior to API 27, Bionic includes a null entry for /system/bin/linker.
+  if (!info->dlpi_name) {
     EXPECT_EQ(info->dlpi_addr, 0u);
     EXPECT_EQ(info->dlpi_phnum, 0u);
+    EXPECT_EQ(info->dlpi_phdr, nullptr);
     return 0;
   }
 #endif
 
+  // Bionic doesn't always set both of these addresses for the vdso and
+  // /system/bin/linker, but it does always set one of them.
+  VMAddress module_addr = info->dlpi_phdr
+                              ? FromPointerCast<LinuxVMAddress>(info->dlpi_phdr)
+                              : info->dlpi_addr;
+
   // TODO(jperaza): This can use a range map when one is available.
   bool found = false;
   for (const auto& module : *modules) {
-    if (module.elf_reader && phdr_addr >= module.elf_reader->Address() &&
-        phdr_addr < module.elf_reader->Address() + module.elf_reader->Size()) {
+    if (module.elf_reader && module_addr >= module.elf_reader->Address() &&
+        module_addr <
+            module.elf_reader->Address() + module.elf_reader->Size()) {
       found = true;
       break;
     }
@@ -535,7 +541,8 @@
 #endif  // !OS_ANDROID || !ARCH_CPU_ARMEL || __ANDROID_API__ >= 21
 }
 
-bool WriteTestModule(const base::FilePath& module_path) {
+bool WriteTestModule(const base::FilePath& module_path,
+                     const std::string& soname) {
 #if defined(ARCH_CPU_64_BITS)
   using Ehdr = Elf64_Ehdr;
   using Phdr = Elf64_Phdr;
@@ -565,6 +572,7 @@
       Dyn symtab;
       Dyn strsz;
       Dyn syment;
+      Dyn soname;
       Dyn null;
     } dynamic_array;
     struct {
@@ -573,8 +581,9 @@
       Elf32_Word bucket;
       Elf32_Word chain;
     } hash_table;
+    char string_table[32];
     struct {
-    } string_table;
+    } section_header_string_table;
     struct {
       Sym und_symbol;
     } symbol_table;
@@ -582,6 +591,7 @@
       Shdr null;
       Shdr dynamic;
       Shdr string_table;
+      Shdr section_header_string_table;
     } shdr_table;
   } module = {};
 
@@ -624,7 +634,9 @@
   module.ehdr.e_shoff = offsetof(decltype(module), shdr_table);
   module.ehdr.e_shentsize = sizeof(Shdr);
   module.ehdr.e_shnum = sizeof(module.shdr_table) / sizeof(Shdr);
-  module.ehdr.e_shstrndx = SHN_UNDEF;
+  module.ehdr.e_shstrndx =
+      offsetof(decltype(module.shdr_table), section_header_string_table) /
+      sizeof(Shdr);
 
   constexpr size_t load2_vaddr = 0x200000;
 
@@ -666,6 +678,9 @@
   module.dynamic_array.strsz.d_un.d_val = sizeof(module.string_table);
   module.dynamic_array.syment.d_tag = DT_SYMENT;
   module.dynamic_array.syment.d_un.d_val = sizeof(Sym);
+  constexpr size_t kSonameOffset = 1;
+  module.dynamic_array.soname.d_tag = DT_SONAME;
+  module.dynamic_array.soname.d_un.d_val = kSonameOffset;
 
   module.dynamic_array.null.d_tag = DT_NULL;
 
@@ -674,6 +689,10 @@
   module.hash_table.bucket = 0;
   module.hash_table.chain = 0;
 
+  CHECK_GE(sizeof(module.string_table), soname.size() + 2);
+  module.string_table[0] = '\0';
+  memcpy(&module.string_table[kSonameOffset], soname.c_str(), soname.size());
+
   module.shdr_table.null.sh_type = SHT_NULL;
 
   module.shdr_table.dynamic.sh_name = 0;
@@ -689,6 +708,14 @@
   module.shdr_table.string_table.sh_type = SHT_STRTAB;
   module.shdr_table.string_table.sh_offset =
       offsetof(decltype(module), string_table);
+  module.shdr_table.string_table.sh_size = sizeof(module.string_table);
+
+  module.shdr_table.section_header_string_table.sh_name = 0;
+  module.shdr_table.section_header_string_table.sh_type = SHT_STRTAB;
+  module.shdr_table.section_header_string_table.sh_offset =
+      offsetof(decltype(module), section_header_string_table);
+  module.shdr_table.section_header_string_table.sh_size =
+      sizeof(module.section_header_string_table);
 
   FileWriter writer;
   if (!writer.Open(module_path,
@@ -706,11 +733,12 @@
   return true;
 }
 
-ScopedModuleHandle LoadTestModule(const std::string& module_name) {
+ScopedModuleHandle LoadTestModule(const std::string& module_name,
+                                  const std::string& module_soname) {
   base::FilePath module_path(
       TestPaths::Executable().DirName().Append(module_name));
 
-  if (!WriteTestModule(module_path)) {
+  if (!WriteTestModule(module_path, module_soname)) {
     return ScopedModuleHandle(nullptr);
   }
   EXPECT_TRUE(IsRegularFile(module_path));
@@ -746,7 +774,9 @@
 
 TEST(ProcessReaderLinux, SelfModules) {
   const std::string module_name = "test_module.so";
-  ScopedModuleHandle empty_test_module(LoadTestModule(module_name));
+  const std::string module_soname = "test_module_soname";
+  ScopedModuleHandle empty_test_module(
+      LoadTestModule(module_name, module_soname));
   ASSERT_TRUE(empty_test_module.valid());
 
   FakePtraceConnection connection;
@@ -756,12 +786,12 @@
   ASSERT_TRUE(process_reader.Initialize(&connection));
 
   ExpectModulesFromSelf(process_reader.Modules());
-  ExpectTestModule(&process_reader, module_name);
+  ExpectTestModule(&process_reader, module_soname);
 }
 
 class ChildModuleTest : public Multiprocess {
  public:
-  ChildModuleTest() : Multiprocess(), module_name_("test_module.so") {}
+  ChildModuleTest() : Multiprocess(), module_soname_("test_module_soname") {}
   ~ChildModuleTest() = default;
 
  private:
@@ -776,11 +806,12 @@
     ASSERT_TRUE(process_reader.Initialize(&connection));
 
     ExpectModulesFromSelf(process_reader.Modules());
-    ExpectTestModule(&process_reader, module_name_);
+    ExpectTestModule(&process_reader, module_soname_);
   }
 
   void MultiprocessChild() override {
-    ScopedModuleHandle empty_test_module(LoadTestModule(module_name_));
+    ScopedModuleHandle empty_test_module(
+        LoadTestModule("test_module.so", module_soname_));
     ASSERT_TRUE(empty_test_module.valid());
 
     char c = 0;
@@ -789,7 +820,7 @@
     CheckedReadFileAtEOF(ReadPipeHandle());
   }
 
-  const std::string module_name_;
+  const std::string module_soname_;
 
   DISALLOW_COPY_AND_ASSIGN(ChildModuleTest);
 };
diff --git a/third_party/crashpad/crashpad/snapshot/minidump/minidump_context_converter.cc b/third_party/crashpad/crashpad/snapshot/minidump/minidump_context_converter.cc
index 0c840de..24d2585 100644
--- a/third_party/crashpad/crashpad/snapshot/minidump/minidump_context_converter.cc
+++ b/third_party/crashpad/crashpad/snapshot/minidump/minidump_context_converter.cc
@@ -14,6 +14,8 @@
 
 #include "snapshot/minidump/minidump_context_converter.h"
 
+#include <string.h>
+
 #include "base/stl_util.h"
 #include "minidump/minidump_context.h"
 
diff --git a/third_party/crashpad/crashpad/util/linux/ptrace_client.cc b/third_party/crashpad/crashpad/util/linux/ptrace_client.cc
index f097ad9..43214a1 100644
--- a/third_party/crashpad/crashpad/util/linux/ptrace_client.cc
+++ b/third_party/crashpad/crashpad/util/linux/ptrace_client.cc
@@ -16,6 +16,7 @@
 
 #include <errno.h>
 #include <stdio.h>
+#include <string.h>
 
 #include <string>
 
diff --git a/third_party/crashpad/crashpad/util/net/http_multipart_builder.cc b/third_party/crashpad/crashpad/util/net/http_multipart_builder.cc
index 267960b..dda46aa 100644
--- a/third_party/crashpad/crashpad/util/net/http_multipart_builder.cc
+++ b/third_party/crashpad/crashpad/util/net/http_multipart_builder.cc
@@ -14,6 +14,7 @@
 
 #include "util/net/http_multipart_builder.h"
 
+#include <string.h>
 #include <sys/types.h>
 
 #include <utility>
diff --git a/third_party/crashpad/crashpad/util/net/http_transport_socket.cc b/third_party/crashpad/crashpad/util/net/http_transport_socket.cc
index 4dd01b6..b9c6c9c 100644
--- a/third_party/crashpad/crashpad/util/net/http_transport_socket.cc
+++ b/third_party/crashpad/crashpad/util/net/http_transport_socket.cc
@@ -17,6 +17,7 @@
 #include <fcntl.h>
 #include <netdb.h>
 #include <poll.h>
+#include <string.h>
 #include <sys/socket.h>
 
 #include "base/logging.h"
diff --git a/third_party/crashpad/crashpad/util/process/process_memory.cc b/third_party/crashpad/crashpad/util/process/process_memory.cc
index ab87b94..3125e6f 100644
--- a/third_party/crashpad/crashpad/util/process/process_memory.cc
+++ b/third_party/crashpad/crashpad/util/process/process_memory.cc
@@ -14,6 +14,8 @@
 
 #include "util/process/process_memory.h"
 
+#include <string.h>
+
 #include <algorithm>
 
 #include "base/logging.h"
diff --git a/third_party/crashpad/crashpad/util/stream/log_output_stream.cc b/third_party/crashpad/crashpad/util/stream/log_output_stream.cc
index 03c0a5a..e35bb3b3 100644
--- a/third_party/crashpad/crashpad/util/stream/log_output_stream.cc
+++ b/third_party/crashpad/crashpad/util/stream/log_output_stream.cc
@@ -14,6 +14,8 @@
 
 #include "util/stream/log_output_stream.h"
 
+#include <string.h>
+
 #include <algorithm>
 
 #include "base/logging.h"
diff --git a/tools/binary_size/generate_milestone_reports.py b/tools/binary_size/generate_milestone_reports.py
index 61c81da..be7d1b5 100755
--- a/tools/binary_size/generate_milestone_reports.py
+++ b/tools/binary_size/generate_milestone_reports.py
@@ -71,8 +71,9 @@
     '78.0.3904.62',
     '79.0.3945.136',
     '80.0.3987.99',
-    '81.0.4044.96',  # Beta
-    '83.0.4103.5',  # Canary
+    '81.0.4044.138',
+    '83.0.4103.60',
+    '84.0.4147.20',  # Canary
 ]
 
 
diff --git a/tools/clang/rewrite_raw_ptr_fields/RewriteRawPtrFields.cpp b/tools/clang/rewrite_raw_ptr_fields/RewriteRawPtrFields.cpp
index 3f439de4..25c6bf6 100644
--- a/tools/clang/rewrite_raw_ptr_fields/RewriteRawPtrFields.cpp
+++ b/tools/clang/rewrite_raw_ptr_fields/RewriteRawPtrFields.cpp
@@ -270,6 +270,47 @@
   return Node.getBeginLoc().isMacroID();
 }
 
+// If |field_decl| declares a field in an implicit template specialization, then
+// finds and returns the corresponding FieldDecl from the template definition.
+// Otherwise, just returns the original |field_decl| argument.
+const clang::FieldDecl* GetExplicitDecl(const clang::FieldDecl* field_decl) {
+  if (field_decl->isAnonymousStructOrUnion())
+    return field_decl;  // Safe fallback - |field_decl| is not a pointer field.
+
+  const clang::CXXRecordDecl* record_decl =
+      clang::dyn_cast<clang::CXXRecordDecl>(field_decl->getParent());
+  if (!record_decl)
+    return field_decl;  // Non-C++ records are never template instantiations.
+
+  const clang::CXXRecordDecl* pattern_decl =
+      record_decl->getTemplateInstantiationPattern();
+  if (!pattern_decl)
+    return field_decl;  // |pattern_decl| is not a template instantiation.
+
+  if (record_decl->getTemplateSpecializationKind() !=
+      clang::TemplateSpecializationKind::TSK_ImplicitInstantiation) {
+    return field_decl;  // |field_decl| was in an *explicit* specialization.
+  }
+
+  // Find the field decl with the same name in |pattern_decl|.
+  clang::DeclContextLookupResult lookup_result =
+      pattern_decl->lookup(field_decl->getDeclName());
+  assert(!lookup_result.empty());
+  const clang::NamedDecl* found_decl = lookup_result.front();
+  assert(found_decl);
+  field_decl = clang::dyn_cast<clang::FieldDecl>(found_decl);
+  assert(field_decl);
+  return field_decl;
+}
+
+AST_MATCHER_P(clang::FieldDecl,
+              hasExplicitDecl,
+              clang::ast_matchers::internal::Matcher<clang::FieldDecl>,
+              InnerMatcher) {
+  const clang::FieldDecl* explicit_field_decl = GetExplicitDecl(&Node);
+  return InnerMatcher.matches(*explicit_field_decl, Finder, Builder);
+}
+
 // Matcher for FieldDecl that has a TypeLoc with a unique start location
 // (i.e. has a TypeLoc that is not shared with any other FieldDecl).
 //
@@ -498,7 +539,8 @@
   //   additional work and should cause related fields to be emitted as
   //   candidates for the --field-filter-file parameter.
   auto affected_member_expr_matcher =
-      memberExpr(member(field_decl_matcher)).bind("affectedMemberExpr");
+      memberExpr(member(fieldDecl(hasExplicitDecl(field_decl_matcher))))
+          .bind("affectedMemberExpr");
   auto affected_implicit_expr_matcher = implicitCastExpr(has(expr(anyOf(
       // Only single implicitCastExpr is present in case of:
       // |auto* v = s.ptr_field;|
diff --git a/tools/clang/rewrite_raw_ptr_fields/fields-to-ignore.txt b/tools/clang/rewrite_raw_ptr_fields/fields-to-ignore.txt
index b6e306f..8224544 100644
--- a/tools/clang/rewrite_raw_ptr_fields/fields-to-ignore.txt
+++ b/tools/clang/rewrite_raw_ptr_fields/fields-to-ignore.txt
@@ -99,6 +99,10 @@
 ui::AXPlatformNodeAuraLinux::atk_hyperlink_
 PrintDialogGtk::dialog_
 
+# Populated manually - using nmap or base::AllocPages directly
+blink::GCInfoTable::table_
+disk_cache::MappedFile::buffer_
+
 # Populated manually, because of in-out-arg usage.
 # (not sure why it wasn't caught by the rewriter when populating the list below).
 ui::AXPlatformNodeAuraLinux::document_parent_
diff --git a/tools/clang/rewrite_raw_ptr_fields/tests/affected-expr-expected.cc b/tools/clang/rewrite_raw_ptr_fields/tests/affected-expr-expected.cc
index b4fb271..e9073e4 100644
--- a/tools/clang/rewrite_raw_ptr_fields/tests/affected-expr-expected.cc
+++ b/tools/clang/rewrite_raw_ptr_fields/tests/affected-expr-expected.cc
@@ -183,3 +183,78 @@
 }
 
 }  // namespace generated_code_tests
+
+namespace affected_implicit_template_specialization {
+
+template <typename T, typename T2>
+struct MyTemplate {
+  CheckedPtr<T> t_ptr;
+  CheckedPtr<T2> t2_ptr;
+
+  struct NestedStruct {
+    CheckedPtr<SomeClass> nested_ptr_field;
+    CheckedPtr<T> nested_t_ptr_field;
+  };
+  NestedStruct nested_struct_field;
+};
+
+template <typename T3>
+struct MyTemplate<SomeClass, T3> {
+  CheckedPtr<SomeClass> some_ptr;
+  CheckedPtr<T3> t3_ptr;
+};
+
+// The example that forces explicit |isAnonymousStructOrUnion| checks in
+// the implementation of GetExplicitDecl.  The example is based on
+// buildtools/third_party/libc++/trunk/include/string.
+template <typename T>
+struct MyStringTemplate {
+  struct NestedStruct {
+    union {
+      long l;
+      short s;
+      CheckedPtr<T> t_ptr;
+      CheckedPtr<int> i_ptr;
+    };  // Unnamed / anonymous union *field*.
+
+    struct {
+      long l2;
+      short s2;
+      CheckedPtr<T> t_ptr2;
+      CheckedPtr<int> i_ptr2;
+    };  // Unnamed / anonymous struct *field*.
+  };
+  NestedStruct s;
+};
+
+void MyPrintf(const char* fmt, ...) {}
+
+void foo() {
+  // |s.t_ptr| comes from implicit template specialization (which needs to be
+  // skipped for rewriting, but should be included for appending |.get()|).
+  //
+  // Expected rewrite: MyPrintf("%p", s.t_ptr.get());
+  MyTemplate<int, int> s;
+  MyPrintf("%p", s.t_ptr.get());
+
+  // |s.some_ptr| and |s.t2_ptr| come from implicit template specialization or a
+  // partial template specialization.
+  //
+  // Expected rewrite: MyPrintf("%p", s.some_ptr.get(), s.t3_ptr.get());
+  MyTemplate<SomeClass, int> s2;
+  MyPrintf("%p %p", s2.some_ptr.get(), s2.t3_ptr.get());
+
+  // Nested structs require extra care when trying to look up the non-implicit
+  // field definition.  Expected rewrite: adding |.get()| suffix.
+  MyPrintf("%p", s.nested_struct_field.nested_ptr_field.get());
+  MyPrintf("%p", s.nested_struct_field.nested_t_ptr_field.get());
+
+  // Lines below are added mainly to Force implicit specialization of
+  // MyStringTemplate (to force explicit |isAnonymousStructOrUnion| checks in
+  // the rewriter).  Still, the expected rewrite is: appending |.get()| to the
+  // printf arg.
+  MyStringTemplate<void> mst;
+  MyPrintf("%p %p", mst.s.t_ptr.get(), mst.s.t_ptr2.get());
+}
+
+}  // namespace affected_implicit_template_specialization
diff --git a/tools/clang/rewrite_raw_ptr_fields/tests/affected-expr-original.cc b/tools/clang/rewrite_raw_ptr_fields/tests/affected-expr-original.cc
index 0e7f92c..a161313 100644
--- a/tools/clang/rewrite_raw_ptr_fields/tests/affected-expr-original.cc
+++ b/tools/clang/rewrite_raw_ptr_fields/tests/affected-expr-original.cc
@@ -182,3 +182,78 @@
 }
 
 }  // namespace generated_code_tests
+
+namespace affected_implicit_template_specialization {
+
+template <typename T, typename T2>
+struct MyTemplate {
+  T* t_ptr;
+  T2* t2_ptr;
+
+  struct NestedStruct {
+    SomeClass* nested_ptr_field;
+    T* nested_t_ptr_field;
+  };
+  NestedStruct nested_struct_field;
+};
+
+template <typename T3>
+struct MyTemplate<SomeClass, T3> {
+  SomeClass* some_ptr;
+  T3* t3_ptr;
+};
+
+// The example that forces explicit |isAnonymousStructOrUnion| checks in
+// the implementation of GetExplicitDecl.  The example is based on
+// buildtools/third_party/libc++/trunk/include/string.
+template <typename T>
+struct MyStringTemplate {
+  struct NestedStruct {
+    union {
+      long l;
+      short s;
+      T* t_ptr;
+      int* i_ptr;
+    };  // Unnamed / anonymous union *field*.
+
+    struct {
+      long l2;
+      short s2;
+      T* t_ptr2;
+      int* i_ptr2;
+    };  // Unnamed / anonymous struct *field*.
+  };
+  NestedStruct s;
+};
+
+void MyPrintf(const char* fmt, ...) {}
+
+void foo() {
+  // |s.t_ptr| comes from implicit template specialization (which needs to be
+  // skipped for rewriting, but should be included for appending |.get()|).
+  //
+  // Expected rewrite: MyPrintf("%p", s.t_ptr.get());
+  MyTemplate<int, int> s;
+  MyPrintf("%p", s.t_ptr);
+
+  // |s.some_ptr| and |s.t2_ptr| come from implicit template specialization or a
+  // partial template specialization.
+  //
+  // Expected rewrite: MyPrintf("%p", s.some_ptr.get(), s.t3_ptr.get());
+  MyTemplate<SomeClass, int> s2;
+  MyPrintf("%p %p", s2.some_ptr, s2.t3_ptr);
+
+  // Nested structs require extra care when trying to look up the non-implicit
+  // field definition.  Expected rewrite: adding |.get()| suffix.
+  MyPrintf("%p", s.nested_struct_field.nested_ptr_field);
+  MyPrintf("%p", s.nested_struct_field.nested_t_ptr_field);
+
+  // Lines below are added mainly to Force implicit specialization of
+  // MyStringTemplate (to force explicit |isAnonymousStructOrUnion| checks in
+  // the rewriter).  Still, the expected rewrite is: appending |.get()| to the
+  // printf arg.
+  MyStringTemplate<void> mst;
+  MyPrintf("%p %p", mst.s.t_ptr, mst.s.t_ptr2);
+}
+
+}  // namespace affected_implicit_template_specialization
diff --git a/tools/clang/rewrite_raw_ptr_fields/tests/various-types-expected.cc b/tools/clang/rewrite_raw_ptr_fields/tests/various-types-expected.cc
index 6f4b90a..73f5366 100644
--- a/tools/clang/rewrite_raw_ptr_fields/tests/various-types-expected.cc
+++ b/tools/clang/rewrite_raw_ptr_fields/tests/various-types-expected.cc
@@ -152,6 +152,13 @@
     CheckedPtr<SomeClass> inner_ptr;
   } * ptr_to_non_free_standing_struct2;
 
+  // The following is an unnamed/anonymous, free-standing struct.
+  //
+  // Expected rewrite: ??? (as long as there are no overlapping replacements).
+  struct {
+    CheckedPtr<SomeClass> inner_ptr;
+  } * ptr_to_non_free_standing_struct3;
+
   // Despite avoiding the problems in NonFreeStandingStruct and
   // NonFreeStandingStruct2 above, we should still rewrite the example below.
   struct FreeStandingStruct {
diff --git a/tools/clang/rewrite_raw_ptr_fields/tests/various-types-original.cc b/tools/clang/rewrite_raw_ptr_fields/tests/various-types-original.cc
index c175467..b1a3eaef 100644
--- a/tools/clang/rewrite_raw_ptr_fields/tests/various-types-original.cc
+++ b/tools/clang/rewrite_raw_ptr_fields/tests/various-types-original.cc
@@ -150,6 +150,13 @@
     SomeClass* inner_ptr;
   } * ptr_to_non_free_standing_struct2;
 
+  // The following is an unnamed/anonymous, free-standing struct.
+  //
+  // Expected rewrite: ??? (as long as there are no overlapping replacements).
+  struct {
+    SomeClass* inner_ptr;
+  } * ptr_to_non_free_standing_struct3;
+
   // Despite avoiding the problems in NonFreeStandingStruct and
   // NonFreeStandingStruct2 above, we should still rewrite the example below.
   struct FreeStandingStruct {
diff --git a/tools/ipc_fuzzer/message_tools/message_util.cc b/tools/ipc_fuzzer/message_tools/message_util.cc
index b598fa4..d77b2973 100644
--- a/tools/ipc_fuzzer/message_tools/message_util.cc
+++ b/tools/ipc_fuzzer/message_tools/message_util.cc
@@ -127,8 +127,9 @@
            args[0], base::FilePath::StringType(1, ','),
            base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
     ipc_fuzzer::MessageVector message_vector;
-    if (!ipc_fuzzer::MessageFile::Read(base::FilePath(name), &message_vector))
+    if (!ipc_fuzzer::MessageFile::Read(base::FilePath(name), &message_vector)) {
       return EXIT_FAILURE;
+    }
     input_message_vector.insert(input_message_vector.end(),
                                 std::make_move_iterator(message_vector.begin()),
                                 std::make_move_iterator(message_vector.end()));
diff --git a/tools/ipc_fuzzer/scripts/ipc_fuzzer_gen.py b/tools/ipc_fuzzer/scripts/ipc_fuzzer_gen.py
index 2c1bbcf..635ed06 100644
--- a/tools/ipc_fuzzer/scripts/ipc_fuzzer_gen.py
+++ b/tools/ipc_fuzzer/scripts/ipc_fuzzer_gen.py
@@ -44,7 +44,7 @@
     utils.create_flags_file(ipcdump_testcase_path)
 
   def main(self):
-    for _ in xrange(self.args.no_of_files):
+    for _ in range(self.args.no_of_files):
       self.generate_ipcdump_testcase()
 
     return 0
diff --git a/tools/ipc_fuzzer/scripts/ipc_fuzzer_mut.py b/tools/ipc_fuzzer/scripts/ipc_fuzzer_mut.py
index 5045b44..70408984 100644
--- a/tools/ipc_fuzzer/scripts/ipc_fuzzer_mut.py
+++ b/tools/ipc_fuzzer/scripts/ipc_fuzzer_mut.py
@@ -74,7 +74,7 @@
 
   def main(self):
     self.set_corpus()
-    for _ in xrange(self.args.no_of_files):
+    for _ in range(self.args.no_of_files):
       self.create_mutated_ipcdump_testcase()
 
     return 0
diff --git a/tools/ipc_fuzzer/scripts/utils.py b/tools/ipc_fuzzer/scripts/utils.py
index 3f19845..0b2245c 100644
--- a/tools/ipc_fuzzer/scripts/utils.py
+++ b/tools/ipc_fuzzer/scripts/utils.py
@@ -21,7 +21,7 @@
 COMMON_LAUNCH_PREFIXES = [
     '--renderer-cmd-prefix',
 ]
-UNCOMMON_LAUNCH_PEFIXES = [
+UNCOMMON_LAUNCH_PREFIXES = [
     '--plugin-launcher',
     '--ppapi-plugin-launcher',
     '--utility-cmd-prefix',
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index e745e3464..882aa16 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -14856,6 +14856,14 @@
   </description>
 </action>
 
+<action name="MobileWebContextMenuOpenInNewWindow">
+  <owner>marq@chromium.org</owner>
+  <owner>djean@chromium.org</owner>
+  <description>
+    Recorded when user taps Open In New Window in context menu. iOS only.
+  </description>
+</action>
+
 <action name="MobileWebContextMenuOpenJS">
   <owner>eugenebut@chromium.org</owner>
   <owner>michaeldo@chromium.org</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 960b46b..2e2e64c 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -15428,6 +15428,12 @@
   <int value="7" label="Periodic Background Sync"/>
 </enum>
 
+<enum name="DevToolsDualScreenDeviceEmulated">
+  <int value="0" label="Dual-screen or fold device selected"/>
+  <int value="1" label="Dual-screen span mode selected"/>
+  <int value="2" label="Platform dual-screen support used"/>
+</enum>
+
 <enum name="DevToolsIssuesPanelOpenedFrom">
   <int value="0" label="Console Info Bar"/>
   <int value="1" label="Learn More Link COEP"/>
@@ -20459,6 +20465,7 @@
   <int value="709" label="ReportDeviceFanInfo"/>
   <int value="710" label="ReportDeviceVpdInfo"/>
   <int value="711" label="EnableExperimentalPolicies"/>
+  <int value="712" label="PluginVmDataCollectionAllowed"/>
 </enum>
 
 <enum name="EnterprisePolicyDeviceIdValidity">
@@ -29577,6 +29584,15 @@
   <int value="7" label="Unknown Error"/>
 </enum>
 
+<enum name="GaiaRemoteConsentFlowResult">
+  <int value="0" label="Success"/>
+  <int value="1" label="Window was closed"/>
+  <int value="2" label="Failed to load the consent page"/>
+  <int value="3" label="Failed to set accounts in cookies"/>
+  <int value="4" label="Failed to parse the consent result"/>
+  <int value="5" label="Consent wasn't granted"/>
+</enum>
+
 <enum name="GaiaServiceType">
   <int value="0" label="No Gaia response header"/>
   <int value="1" label="Logout all existing sessions"/>
@@ -41121,6 +41137,7 @@
   <int value="740056959" label="ImeServiceConnectable:enabled"/>
   <int value="740619684" label="ExtensionsToolbarMenu:enabled"/>
   <int value="742083923" label="MimeHandlerViewInCrossProcessFrame:disabled"/>
+  <int value="744342941" label="SafetyCheckChromeCleanerChild:enabled"/>
   <int value="745541471" label="PaintHolding:disabled"/>
   <int value="745783589" label="translate-force-trigger-on-english"/>
   <int value="745868416" label="disable-system-timezone-automatic-detection"/>
@@ -41165,6 +41182,7 @@
   <int value="799680074" label="ContextualSearchTranslationModel:enabled"/>
   <int value="803282885" label="PreferHtmlOverPlugins:disabled"/>
   <int value="805661595" label="ChromeosVideoDecoder:enabled"/>
+  <int value="805882800" label="SafetyCheckChromeCleanerChild:disabled"/>
   <int value="806035639" label="EnableNeuralPalmDetectionFilter:disabled"/>
   <int value="806334184" label="AndroidSpellChecker:enabled"/>
   <int value="806783713" label="DesktopPWAsTabStripLinkCapturing:enabled"/>
@@ -50709,6 +50727,161 @@
   <int value="9" label="TokenDisabled"/>
 </enum>
 
+<enum name="OsSetting">
+  <int value="0" label="Configure Ethernet"/>
+  <int value="1" label="Ethernet: Automatically Configure IP Address"/>
+  <int value="2" label="Ethernet: DNS"/>
+  <int value="3" label="Ethernet: Proxy"/>
+  <int value="4" label="Wi-Fi: On/Off"/>
+  <int value="5" label="Disconnect Wi-Fi Network"/>
+  <int value="6" label="Prefer Wi-Fi Network"/>
+  <int value="7" label="Forget Wi-Fi Network"/>
+  <int value="8" label="Configure Wi-Fi"/>
+  <int value="9" label="Wi-Fi: Automatically Configure IP Address"/>
+  <int value="10" label="Wi-Fi: DNS"/>
+  <int value="11" label="Wi-Fi: Proxy"/>
+  <int value="12" label="Wi-Fi: Auto Connect To Network"/>
+  <int value="13" label="Mobile: On/Off"/>
+  <int value="14" label="Cellular: Sim Lock"/>
+  <int value="15" label="Cellular: Roaming"/>
+  <int value="16" label="Cellular: Apn"/>
+  <int value="17" label="Disconnect Cellular Network"/>
+  <int value="18" label="Cellular: Automatically Configure IP Address"/>
+  <int value="19" label="Cellular: DNS"/>
+  <int value="20" label="Cellular: Proxy"/>
+  <int value="21" label="Cellular: Automatically Connect To Network"/>
+  <int value="22" label="Instant Tethering: On/Off"/>
+  <int value="23" label="Disconnect Tether Network"/>
+  <int value="100" label="Bluetooth: On/Off"/>
+  <int value="101" label="Bluetooth: Connect To Device"/>
+  <int value="102" label="Bluetooth: Disconnect From Device"/>
+  <int value="103" label="Bluetooth: Pair Device"/>
+  <int value="104" label="Bluetooth: Unpair Device"/>
+  <int value="200" label="Set Up MultiDevice"/>
+  <int value="201" label="Verify MultiDevice Setup"/>
+  <int value="202" label="MultiDevice On/Off"/>
+  <int value="203" label="Smart Lock: On/Off"/>
+  <int value="204" label="Smart Lock: Unlock Or Sign In"/>
+  <int value="205" label="Messages: Set Up"/>
+  <int value="206" label="Messages: On/Off"/>
+  <int value="207" label="Forget Phone"/>
+  <int value="300" label="Add Account"/>
+  <int value="301" label="Remove Account"/>
+  <int value="302" label="Sync On/Off"/>
+  <int value="303" label="Lock Screen"/>
+  <int value="304" label="Change Auth Pin"/>
+  <int value="305" label="Guest Browsing"/>
+  <int value="306" label="Show Usernames And Photos At Sign In"/>
+  <int value="307" label="Restrict Sign In"/>
+  <int value="308" label="Add To User Whitelist"/>
+  <int value="309" label="Remove From User Whitelist"/>
+  <int value="310" label="Add Kerberos Ticket"/>
+  <int value="311" label="Remove Kerberos Ticket"/>
+  <int value="312" label="Set Active Kerberos Ticket"/>
+  <int value="313" label="Add Fingerprint"/>
+  <int value="314" label="Remove Fingerprint"/>
+  <int value="315" label="Set Up Parental Controls"/>
+  <int value="400" label="Touchpad: Tap-To-Click"/>
+  <int value="401" label="Touchpad: Tap Dragging"/>
+  <int value="402" label="Touchpad: Reverse Scrolling"/>
+  <int value="403" label="Touchpad: Acceleration"/>
+  <int value="404" label="Touchpad: Scroll Acceleration"/>
+  <int value="405" label="Touchpad: Speed"/>
+  <int value="406" label="Mouse: Swap Primary Buttons"/>
+  <int value="407" label="Mouse: Reverse Scrolling"/>
+  <int value="408" label="Mouse: Acceleration"/>
+  <int value="409" label="Mouse: Scroll Acceleration"/>
+  <int value="410" label="Mouse: Speed"/>
+  <int value="411" label="Keyboard: Function Keys"/>
+  <int value="412" label="Keyboard: Auto Repeat"/>
+  <int value="413" label="Keyboard: Shortcuts"/>
+  <int value="414" label="Display: Size"/>
+  <int value="415" label="Night Light"/>
+  <int value="416" label="Stylus: Tools In Shelf"/>
+  <int value="417" label="Stylus: Note Taking App"/>
+  <int value="418" label="Stylus: Note Taking From Lock Screen"/>
+  <int value="419" label="Stylus: Latest Note On Lock Screen"/>
+  <int value="420" label="Display: Orientation"/>
+  <int value="421" label="Display: Arrangement"/>
+  <int value="422" label="Power: Idle Behavior While Charging"/>
+  <int value="423" label="Power: Source"/>
+  <int value="424" label="Sleep When Laptop Lid is Closed"/>
+  <int value="425" label="Display: Resolution"/>
+  <int value="426" label="Display: Refresh Rate"/>
+  <int value="427" label="Remove DLC"/>
+  <int value="428" label="Display: Mirroring"/>
+  <int value="429" label="Allow Windows To Span Displays"/>
+  <int value="430" label="Ambient Colors"/>
+  <int value="431" label="Touchscreen Calibration"/>
+  <int value="432" label="Night Light Color Temperature"/>
+  <int value="433" label="Power Idle Behavior While On Battery"/>
+  <int value="500" label="Open Wallpaper"/>
+  <int value="501" label="Ambient Mode On/Off"/>
+  <int value="502" label="Ambient Mode Source"/>
+  <int value="503" label="Change Device Account Image"/>
+  <int value="600" label="Preferred Search Engine"/>
+  <int value="601" label="Assistant: On/Off"/>
+  <int value="602" label="Assistant: Related Info"/>
+  <int value="603" label="Assistant: Quick Answers"/>
+  <int value="604" label="Assistant: Ok Google"/>
+  <int value="605" label="Assistant: Notifications"/>
+  <int value="606" label="Assistant: Voice Input"/>
+  <int value="700" label="Manage Android Preferences"/>
+  <int value="701" label="Remove Play Store"/>
+  <int value="702" label="Turn On Play Store"/>
+  <int value="800" label="Set Up Crostini"/>
+  <int value="801" label="Uninstall Crostini"/>
+  <int value="802" label="Backup Linux Apps And Files"/>
+  <int value="803" label="Restore Linux Apps And Files"/>
+  <int value="804" label="Crostini: Adb Debugging"/>
+  <int value="805" label="Crostini: Disk Resize"/>
+  <int value="806" label="Crostini: Mic Access"/>
+  <int value="807" label="Crostini: Container Upgrade"/>
+  <int value="1000" label="24Hour Clock"/>
+  <int value="1001" label="Change Time Zone"/>
+  <int value="1101" label="Verified Access"/>
+  <int value="1102" label="Keep Wi-Fi On During Sleep"/>
+  <int value="1103" label="Usage Stats And Crash Reports"/>
+  <int value="1200" label="Add Language"/>
+  <int value="1201" label="Show Input Options In Shelf"/>
+  <int value="1202" label="Show Personal Information Suggestions"/>
+  <int value="1300" label="Google Drive Connection"/>
+  <int value="1400" label="Add Printer"/>
+  <int value="1401" label="Saved Printers"/>
+  <int value="1402" label="Print Jobs"/>
+  <int value="1500" label="A11y Quick Settings"/>
+  <int value="1501" label="Chrome Vox"/>
+  <int value="1502" label="Select To Speak"/>
+  <int value="1503" label="Text-To-Speech: Rate"/>
+  <int value="1504" label="Text-To-Speech: Pitch"/>
+  <int value="1505" label="Text-To-Speech: Volume"/>
+  <int value="1506" label="Text-To-Speech: Voice"/>
+  <int value="1507" label="Text-To-Speech: Engines"/>
+  <int value="1508" label="High Contrast Mode"/>
+  <int value="1509" label="Fullscreen Magnifier"/>
+  <int value="1510" label="Docked Magnifier"/>
+  <int value="1511" label="Sticky Keys"/>
+  <int value="1512" label="On Screen Keyboard"/>
+  <int value="1513" label="Dictation"/>
+  <int value="1514" label="Speak-To-Type"/>
+  <int value="1515" label="Highlight Text Caret"/>
+  <int value="1516" label="Auto-Click When Cursor Stops"/>
+  <int value="1517" label="Large Cursor"/>
+  <int value="1518" label="Highlight Cursor While Moving"/>
+  <int value="1519" label="Tablet Navigation Buttons"/>
+  <int value="1520" label="Mono Audio"/>
+  <int value="1521" label="Startup Sound"/>
+  <int value="1522" label="Enable Switch Access"/>
+  <int value="1523" label="Switch Action: Assignment"/>
+  <int value="1524" label="Switch Action: Auto Scan"/>
+  <int value="1525" label="Switch Action: Auto Scan Keyboard"/>
+  <int value="1526" label="Get Image Descriptions From Google"/>
+  <int value="1527" label="Live Captions"/>
+  <int value="1600" label="Powerwash"/>
+  <int value="1700" label="Change Chrome Channel"/>
+  <int value="1701" label="Copy Detailed Build Info"/>
+</enum>
+
 <enum name="OsSettingsProviderError">
   <int value="0" label="Ok"/>
   <int value="1" label="App service unavailable"/>
@@ -50716,6 +50889,87 @@
   <int value="3" label="Search handler unavailable"/>
 </enum>
 
+<enum name="OsSettingsSearchResultType">
+  <int value="0" label="kSection"/>
+  <int value="1" label="kSubpage"/>
+  <int value="2" label="kSetting"/>
+</enum>
+
+<enum name="OsSettingsSection">
+  <int value="0" label="Network"/>
+  <int value="1" label="Bluetooth"/>
+  <int value="2" label="Multi Device"/>
+  <int value="3" label="People"/>
+  <int value="4" label="Device"/>
+  <int value="5" label="Personalization"/>
+  <int value="6" label="Search And Assistant"/>
+  <int value="7" label="Apps"/>
+  <int value="8" label="Crostini"/>
+  <int value="10" label="Date And Time"/>
+  <int value="11" label="Privacy And Security"/>
+  <int value="12" label="Languages And Input"/>
+  <int value="13" label="Files"/>
+  <int value="14" label="Printing"/>
+  <int value="15" label="Accessibility"/>
+  <int value="16" label="Reset"/>
+  <int value="17" label="About Chrome OS"/>
+</enum>
+
+<enum name="OsSettingsSubpage">
+  <int value="0" label="Ethernet Details"/>
+  <int value="1" label="Wifi Networks"/>
+  <int value="2" label="Wifi Details"/>
+  <int value="3" label="Known Networks"/>
+  <int value="4" label="Mobile Data Networks"/>
+  <int value="5" label="Cellular Details"/>
+  <int value="6" label="Tether Details"/>
+  <int value="7" label="Vpn Details"/>
+  <int value="100" label="Bluetooth Devices"/>
+  <int value="200" label="Multi Device Features"/>
+  <int value="201" label="Smart Lock"/>
+  <int value="300" label="My Accounts"/>
+  <int value="301" label="Sync"/>
+  <int value="302" label="Sync (Deprecated)"/>
+  <int value="303" label="Sync Advanced (Deprecated)"/>
+  <int value="304" label="Security And Sign In"/>
+  <int value="305" label="Fingerprint"/>
+  <int value="306" label="Manage Other People"/>
+  <int value="307" label="Kerberos"/>
+  <int value="400" label="Pointers"/>
+  <int value="401" label="Keyboard"/>
+  <int value="402" label="Stylus"/>
+  <int value="403" label="Display"/>
+  <int value="404" label="Storage"/>
+  <int value="405" label="External Storage"/>
+  <int value="406" label="DLC"/>
+  <int value="407" label="Power"/>
+  <int value="500" label="Change Picture"/>
+  <int value="501" label="Ambient Mode"/>
+  <int value="600" label="Assistant"/>
+  <int value="700" label="App Management"/>
+  <int value="701" label="App Details"/>
+  <int value="702" label="Google Play Store"/>
+  <int value="703" label="Plugin Vm Shared Paths"/>
+  <int value="800" label="Crostini Details"/>
+  <int value="801" label="Crostini Manage Shared Folders"/>
+  <int value="802" label="Crostini Usb Preferences"/>
+  <int value="803" label="Crostini Backup And Restore"/>
+  <int value="804" label="Crostini Develop Android Apps"/>
+  <int value="805" label="Crostini Port Forwarding"/>
+  <int value="1000" label="Time Zone"/>
+  <int value="1200" label="Languages And Input Details"/>
+  <int value="1201" label="Manage Input Methods"/>
+  <int value="1202" label="Smart Inputs"/>
+  <int value="1300" label="Network File Shares"/>
+  <int value="1400" label="Printing Details"/>
+  <int value="1500" label="Manage Accessibility"/>
+  <int value="1502" label="Text-To-Speech"/>
+  <int value="1503" label="Switch Access Options"/>
+  <int value="1504" label="Captions"/>
+  <int value="1700" label="About Chrome OS Details"/>
+  <int value="1701" label="Detailed Build Info"/>
+</enum>
+
 <enum name="OsSuite">
   <int value="0" label="Windows Home Edition (or unknown)"/>
   <int value="1" label="Windows Professional/Ultimate Editions"/>
@@ -56811,10 +57065,17 @@
   <int value="21" label="QUIC_CHROMIUM_CLIENT_SESSION_CLOSE_SESSION_ON_ERROR"/>
 </enum>
 
+<enum name="QuickAnswersIntentType">
+  <int value="0" label="kUnknown"/>
+  <int value="1" label="kUnit"/>
+  <int value="2" label="kDictionary"/>
+  <int value="3" label="kTranslation"/>
+</enum>
+
 <enum name="QuickAnswersLoadStatus">
-  <int value="0" label="kNetworkError"/>
-  <int value="1" label="kNoResult"/>
-  <int value="2" label="kSuccess"/>
+  <int value="0" label="kSuccess"/>
+  <int value="1" label="kNetworkError"/>
+  <int value="2" label="kNoResult"/>
 </enum>
 
 <enum name="QuickAnswersResultType">
@@ -65873,6 +66134,25 @@
   <int value="3" label="Use new"/>
 </enum>
 
+<enum name="SyncConsentBehavior">
+  <summary>
+    Behavior of the out-of-box experience (OOBE) sync consent screen.
+  </summary>
+  <int value="0" label="Unknown"/>
+  <int value="1" label="Show"/>
+  <int value="2" label="Skip"/>
+  <int value="3" label="Skip and enable sync"/>
+</enum>
+
+<enum name="SyncConsentUserChoice">
+  <summary>
+    Which button the user clicked in the out-of-box experience (OOBE) sync
+    consent screen.
+  </summary>
+  <int value="0" label="Declined"/>
+  <int value="1" label="Accepted"/>
+</enum>
+
 <enum name="SyncCryptographerPendingKeysState">
   <int value="0" label="Does not have pending keys"/>
   <int value="1" label="Has pending keys"/>
@@ -70014,6 +70294,9 @@
 </enum>
 
 <enum name="VRAssetsComponentUpdateStatus">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <int value="1"
       label="Failed to verify component (component version not known)."/>
   <int value="2"
@@ -70028,6 +70311,9 @@
 </enum>
 
 <enum name="VRAssetsLoadStatus">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <int value="1000"
       label="Successfully loaded assets (component version 0.1)."/>
   <int value="1001"
@@ -70039,6 +70325,9 @@
 </enum>
 
 <enum name="VRComponentStatus">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <int value="0" label="Component is ready to use"/>
   <int value="1" label="Component is not ready to use. Reason unknown."/>
 </enum>
@@ -70064,6 +70353,9 @@
 </enum>
 
 <enum name="VRPresentationStartAction">
+  <obsolete>
+    Removed as of 06/2020.
+  </obsolete>
   <int value="0" label="Other">
     A catch all for presentation sources that are unknown or cannot be specified
     for other reasons.
@@ -70087,6 +70379,9 @@
 </enum>
 
 <enum name="VRSessionStartAction">
+  <obsolete>
+    Removed as of 06/2020.
+  </obsolete>
   <int value="1" label="Headset Activation">
     The user activated a headset. For example, inserted phone in Daydream, or
     put on an Occulus or Vive.
@@ -70105,6 +70400,9 @@
 </enum>
 
 <enum name="VRStartReason">
+  <obsolete>
+    Removed as of 06/2020.
+  </obsolete>
   <int value="1" label="Headset Activation"/>
   <int value="2" label="Presentation Requset"/>
   <int value="3" label="(obsolete) Deep linked app"/>
@@ -70112,6 +70410,9 @@
 </enum>
 
 <enum name="VRSuppressedElement">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <int value="0" label="File chooser was suppressed in VR"/>
   <int value="1" label="Bluetooth picker was suppressed in VR"/>
   <int value="2" label="JS dialog was suppressed in VR (obsolete in M71)"/>
@@ -70137,6 +70438,9 @@
 </enum>
 
 <enum name="VRUnsupportedMode">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <int value="0" label="Unhandled code point in URL"/>
   <int value="1" label="Could not elide URL (obsolete)"/>
   <int value="2" label="Unhandled PageInfo"/>
@@ -70165,6 +70469,9 @@
 </enum>
 
 <enum name="VRVoiceSearchEndState">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <int value="0" label="Voice search in VR opened a search page"/>
   <int value="1" label="Voice search in VR cancelled"/>
   <int value="2" label="Voice search in VR didn't catch phrase or timed out"/>
@@ -71993,6 +72300,11 @@
   <int value="13" label="android_asset or android_res"/>
 </enum>
 
+<enum name="WebViewVisibility">
+  <int value="0" label="NotVisible"/>
+  <int value="1" label="Visible"/>
+</enum>
+
 <enum name="WelcomeSignInPromptOutcome">
   <int value="0" label="User navigated away from page"/>
   <int value="1" label="User clicked the No Thanks button"/>
@@ -74139,6 +74451,9 @@
 </enum>
 
 <enum name="XRSessionRequestDialogAction">
+  <obsolete>
+    Removed as of 06/2020.
+  </obsolete>
   <int value="0" label="UserConsented"/>
   <int value="1" label="UserDenied"/>
   <int value="2" label="UserAbortedConsentFlow"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 67e50efb..1cb350d 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -5434,6 +5434,36 @@
   </summary>
 </histogram>
 
+<histogram name="Android.WebView.Visibility.Global" enum="WebViewVisibility"
+    expires_after="2021-01-01">
+  <owner>idries@chromium.org</owner>
+  <owner>src/android_webview/OWNERS</owner>
+  <summary>
+    Records the global visibility state of WebView in seconds. The Visible
+    bucket counts total seconds that any WebView was visible (the view itself
+    was visible, and was attached to the view hierarchy of a visible window).
+    The NotVisble bucket counts time since WebView initialization for which no
+    WebView was considered visible, or no WebView existed. The total of these
+    two buckets reflects the amount of time covered by metrics collection.
+  </summary>
+</histogram>
+
+<histogram name="Android.WebView.Visibility.PerWebView"
+    enum="WebViewVisibility" expires_after="2021-01-01">
+  <owner>idries@chromium.org</owner>
+  <owner>src/android_webview/OWNERS</owner>
+  <summary>
+    Records per-WebView visibility duration in seconds. The Visible bucket
+    counts the total time in seconds that each WebView was considered visible
+    (the view itself was visible, and was attached to the view hierarchy of a
+    visible window). If more than one WebView is considered visible, then each
+    WebView contributes independently. The NotVisible bucket counts the duration
+    that each WebView exists but not in a visible state. As with the Visible
+    bucket, each WebView contributes independently, and thus this bucket is not
+    incremented when no WebViews exist.
+  </summary>
+</histogram>
+
 <histogram name="AndroidSearchEngineLogo.Events"
     enum="AndroidSearchEngineLogoEvents" expires_after="2020-10-14">
   <owner>wylieb@chromium.org</owner>
@@ -25926,6 +25956,46 @@
   </summary>
 </histogram>
 
+<histogram name="ChromeOS.Settings.SearchResultSectionSelected"
+    enum="OsSettingsSection" expires_after="2020-12-01">
+  <owner>khorimoto@chromium.org</owner>
+  <owner>hsuregan@chromium.org</owner>
+  <owner>cros-customization@google.com</owner>
+  <summary>
+    Section search results clicked by user in the OS settings search box.
+  </summary>
+</histogram>
+
+<histogram name="ChromeOS.Settings.SearchResultSettingSelected"
+    enum="OsSetting" expires_after="2020-12-01">
+  <owner>khorimoto@chromium.org</owner>
+  <owner>hsuregan@chromium.org</owner>
+  <owner>cros-customization@google.com</owner>
+  <summary>
+    Setting search results clicked by user in the OS settings search box.
+  </summary>
+</histogram>
+
+<histogram name="ChromeOS.Settings.SearchResultSubpageSelected"
+    enum="OsSettingsSubpage" expires_after="2020-12-01">
+  <owner>khorimoto@chromium.org</owner>
+  <owner>hsuregan@chromium.org</owner>
+  <owner>cros-customization@google.com</owner>
+  <summary>
+    Subpage search results clicked by user in the OS settings search box.
+  </summary>
+</histogram>
+
+<histogram name="ChromeOS.Settings.SearchResultTypeSelected"
+    enum="OsSettingsSearchResultType" expires_after="2020-12-01">
+  <owner>khorimoto@chromium.org</owner>
+  <owner>hsuregan@chromium.org</owner>
+  <owner>cros-customization@google.com</owner>
+  <summary>
+    Type of search results clicked by user in the OS settings search box.
+  </summary>
+</histogram>
+
 <histogram base="true" name="ChromeOS.Settings.TimeUntilChange" units="ms"
     expires_after="2020-12-01">
 <!-- Name completed by histogram_suffixes name="OsSettingsChangeType" -->
@@ -37731,6 +37801,18 @@
   </summary>
 </histogram>
 
+<histogram name="DevTools.DualScreenDeviceEmulated"
+    enum="DevToolsDualScreenDeviceEmulated" expires_after="M87">
+  <owner>yangguo@chromium.org</owner>
+  <owner>soxia@microsoft.com</owner>
+  <owner>leo.lee@microsoft.com</owner>
+  <summary>
+    Records the usage of dual screen device emulation: a dual screen or fold
+    device is selected for emulation; the span button is hit; or the platform
+    support of dual screen is utilized.
+  </summary>
+</histogram>
+
 <histogram name="DevTools.InspectElement" units="ms" expires_after="M85">
   <owner>alph@chromium.org</owner>
   <owner>yangguo@chromium.org</owner>
@@ -37752,8 +37834,9 @@
 
 <histogram name="DevTools.KeybindSetSettingChanged" enum="DevToolsKeybindSets"
     expires_after="2020-10-31">
+  <owner>yangguo@chromium.org</owner>
   <owner>jalyn@microsoft.com</owner>
-  <owner>edgedevtoolseng@microsoft.com</owner>
+  <owner>leo.lee@microsoft.com</owner>
   <summary>
     Recorded when the user changes which keyboard shortcut presets they are
     using in the DevTools.
@@ -37762,8 +37845,9 @@
 
 <histogram name="DevTools.KeyboardShortcutFired"
     enum="DevToolsKeyboardShortcutAction" expires_after="2020-10-31">
+  <owner>yangguo@microsoft.com</owner>
   <owner>jalyn@microsoft.com</owner>
-  <owner>edgedevtoolseng@microsoft.com</owner>
+  <owner>leo.lee@microsoft.com</owner>
   <summary>
     Recorded when a DevTools keyboard shortcut has been processed and
     successfully executed its action.
@@ -47692,8 +47776,9 @@
 </histogram>
 
 <histogram name="Enterprise.PolicyUpdatePeriod.Device" units="days"
-    expires_after="M84">
-  <owner>antrim@chromium.org</owner>
+    expires_after="M90">
+  <owner>rbock@google.com</owner>
+  <owner>igorcov@chromium.org</owner>
   <summary>Time since last device policy fetch.</summary>
 </histogram>
 
@@ -47704,8 +47789,9 @@
 </histogram>
 
 <histogram name="Enterprise.PolicyUpdatePeriod.User" units="days"
-    expires_after="M77">
-  <owner>antrim@chromium.org</owner>
+    expires_after="M90">
+  <owner>rbock@google.com</owner>
+  <owner>igorcov@chromium.org</owner>
   <summary>Time since last user policy fetch.</summary>
 </histogram>
 
@@ -56132,7 +56218,7 @@
 </histogram>
 
 <histogram name="Extensions.HasPermissions_WebStoreInstall3" enum="Boolean"
-    expires_after="2020-06-01">
+    expires_after="2021-06-01">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
@@ -56147,6 +56233,9 @@
 
 <histogram name="Extensions.HasPermissions_WebStoreInstallAbort3"
     enum="Boolean" expires_after="M85">
+  <obsolete>
+    Code removed 2020-06.
+  </obsolete>
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
@@ -56160,7 +56249,7 @@
 </histogram>
 
 <histogram name="Extensions.HasPermissions_WebStoreInstallCancel3"
-    enum="Boolean" expires_after="2020-06-01">
+    enum="Boolean" expires_after="2021-06-01">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
@@ -59239,7 +59328,7 @@
 </histogram>
 
 <histogram name="FCMInvalidations.ResetClientIDStatus" enum="InstanceIDResult"
-    expires_after="M85">
+    expires_after="M88">
   <owner>tschumann@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -61334,6 +61423,9 @@
 
 <histogram base="true" name="GCM.IgnoredWriteResult" enum="BooleanSuccess"
     expires_after="M85">
+  <obsolete>
+    Removed in 2020-06.
+  </obsolete>
 <!-- Name completed by histogram_suffixes name="IgnoredWriteResultOperation" -->
 
   <owner>tschumann@chromium.org</owner>
@@ -68852,6 +68944,9 @@
 
 <histogram name="InstanceID.GeneratedNewID" enum="BooleanHit"
     expires_after="M85">
+  <obsolete>
+    Removed in 2020-06.
+  </obsolete>
   <owner>tschumann@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -113494,6 +113589,19 @@
   <summary>Time spent on specific OOBE screen grouped by exit reason.</summary>
 </histogram>
 
+<histogram name="OOBE.SyncConsentScreen.Behavior" enum="SyncConsentBehavior"
+    expires_after="2020-12-01">
+  <owner>jamescook@chromium.org</owner>
+  <owner>cros-oac@google.com</owner>
+  <summary>
+    Whether the sync consent screen was shown, skipped (resulting in the default
+    sync behavior), or skipped with sync enabled. Recorded when the screen is
+    closed. The default sync behavior depends on the SplitSettingsSync flag.
+    When SplitSettingsSync is enabled, sync defaults to off, and vice versa.
+    Metric Sync.InitialState provides more detail on the state of sync.
+  </summary>
+</histogram>
+
 <histogram name="OOBE.SyncConsentScreen.ReviewFollowingSetup"
     enum="BooleanChecked" expires_after="2020-10-01">
   <owner>raleksandrov@google.com</owner>
@@ -113504,6 +113612,16 @@
   </summary>
 </histogram>
 
+<histogram name="OOBE.SyncConsentScreen.UserChoice"
+    enum="SyncConsentUserChoice" expires_after="2020-12-01">
+  <owner>jamescook@chromium.org</owner>
+  <owner>cros-oac@google.com</owner>
+  <summary>
+    Which button the user clicked on the out-of-box sync consent screen.
+    Recorded when the user clicks the button, which also closes the screen.
+  </summary>
+</histogram>
+
 <histogram name="OOBE.UpdateScreen.UpdateDownloadingTime" units="ms"
     expires_after="2020-10-01">
   <owner>raleksandrov@google.com</owner>
@@ -120019,11 +120137,13 @@
 </histogram>
 
 <histogram name="PasswordManager.AbleToSavePasswordsOnSuccessfulLogin"
-    enum="BooleanSuccess" expires_after="M85">
+    enum="BooleanSuccess" expires_after="M90">
   <owner>vasilii@chromium.org</owner>
+  <owner>src/components/password_manager/OWNERS</owner>
   <summary>
     Records attempts to prompt user to save a password when password store is
-    not ready for saving passwords. Recorded once per form submission.
+    not ready for saving passwords due to an initialization error. Recorded once
+    per form submission.
   </summary>
 </histogram>
 
@@ -120843,8 +120963,9 @@
 </histogram>
 
 <histogram name="PasswordManager.CleanedUpPasswords" units="units"
-    expires_after="M85">
+    expires_after="M90">
   <owner>vasilii@chromium.org</owner>
+  <owner>src/components/password_manager/OWNERS</owner>
   <summary>
     Collects positive number of undecryptable passwords that were successfully
     deleted when syncing was enabled. Called for sync user for each profile if
@@ -120927,6 +121048,9 @@
 
 <histogram name="PasswordManager.DeleteCorruptedPasswordsResult"
     enum="DeleteCorruptedPasswordsResult" expires_after="M85">
+  <obsolete>
+    Removed as of 06/2020.
+  </obsolete>
   <owner>vasilii@chromium.org</owner>
   <summary>
     Records the result of removing passwords that cannot be decrypted when
@@ -122156,8 +122280,9 @@
 </histogram>
 
 <histogram name="PasswordManager.PasswordStoreInitResult" enum="BooleanSuccess"
-    expires_after="M85">
+    expires_after="M90">
   <owner>vasilii@chromium.org</owner>
+  <owner>src/components/password_manager/OWNERS</owner>
   <summary>
     Success rate of initialization of password store. Recorded for every user
     once on the Chrome profile startup.
@@ -122284,6 +122409,9 @@
 
 <histogram name="PasswordManager.RemovedCorruptedPasswords" units="units"
     expires_after="M85">
+  <obsolete>
+    Removed as of 06/2020.
+  </obsolete>
   <owner>vasilii@chromium.org</owner>
   <summary>
     Collects positive number of inaccessible passwords that were successfully
@@ -135686,6 +135814,16 @@
   </summary>
 </histogram>
 
+<histogram name="QuickAnswers.Intent" enum="QuickAnswersIntentType"
+    expires_after="2020-12-10">
+  <owner>llin@google.com</owner>
+  <owner>croissant-eng@chromium.org</owner>
+  <summary>
+    For quick answer fetch, records the intent generated on-device. ChromeOS
+    only.
+  </summary>
+</histogram>
+
 <histogram name="QuickAnswers.Loading.Duration" units="ms"
     expires_after="2020-12-10">
   <owner>llin@google.com</owner>
@@ -157501,6 +157639,16 @@
   </summary>
 </histogram>
 
+<histogram name="Signin.Extensions.GaiaRemoteConsentFlowResult"
+    enum="GaiaRemoteConsentFlowResult" expires_after="2020-10-04">
+  <owner>alexilin@chromium.org</owner>
+  <owner>droger@chromium.org</owner>
+  <summary>
+    Result of the browser remote consent flow, which is a part of the
+    chrome.identity.getAuthToken() extension API call. Desktop only.
+  </summary>
+</histogram>
+
 <histogram name="Signin.ForceSigninVerificationRequest" enum="BooleanRequested"
     expires_after="M85">
   <owner>zmin@chromium.org</owner>
@@ -181798,6 +181946,9 @@
 
 <histogram base="true" name="VR.Component.Assets.DurationUntilReady.OnEnter"
     units="ms" expires_after="2020-07-01">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <owner>alcooper@chromium.org</owner>
   <owner>xr-dev@chromium.org</owner>
   <summary>
@@ -181808,6 +181959,9 @@
 
 <histogram name="VR.Component.Assets.DurationUntilReady.OnRegisterComponent"
     units="ms" expires_after="2020-07-01">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <owner>alcooper@chromium.org</owner>
   <owner>xr-dev@chromium.org</owner>
   <summary>
@@ -181817,6 +181971,9 @@
 
 <histogram base="true" name="VR.Component.Assets.Status.OnEnter"
     enum="VRComponentStatus" expires_after="2020-07-01">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <owner>alcooper@chromium.org</owner>
   <owner>xr-dev@chromium.org</owner>
   <summary>Status of the VR assets component when entering a VR mode.</summary>
@@ -181824,6 +181981,9 @@
 
 <histogram name="VR.Component.Assets.VersionAndStatus.OnLoad"
     enum="VRAssetsLoadStatus" expires_after="2020-07-01">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <owner>alcooper@chromium.org</owner>
   <owner>xr-dev@chromium.org</owner>
   <summary>
@@ -181836,6 +181996,9 @@
 
 <histogram name="VR.Component.Assets.VersionAndStatus.OnUpdate"
     enum="VRAssetsComponentUpdateStatus" expires_after="2020-07-01">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <owner>alcooper@chromium.org</owner>
   <owner>xr-dev@chromium.org</owner>
   <summary>
@@ -181849,6 +182012,9 @@
 
 <histogram name="VR.EnterVrBrowserWithoutFeatureModule" enum="BooleanSuccess"
     expires_after="2020-07-01">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <owner>alcooper@chromium.org</owner>
   <owner>xr-dev@chromium.org</owner>
   <summary>
@@ -181861,6 +182027,9 @@
 
 <histogram base="true" name="VR.NetworkConnectionType.OnEnter"
     enum="NetworkConnectionType" expires_after="2020-07-01">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <owner>alcooper@chromium.org</owner>
   <owner>xr-dev@chromium.org</owner>
   <summary>Network connection type when entering a VR mode.</summary>
@@ -181868,6 +182037,9 @@
 
 <histogram name="VR.NetworkConnectionType.OnRegisterComponent"
     enum="NetworkConnectionType" expires_after="2020-07-01">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <owner>alcooper@chromium.org</owner>
   <owner>xr-dev@chromium.org</owner>
   <summary>
@@ -181890,6 +182062,9 @@
 
 <histogram name="VR.Shell.EncounteredSuppressedUI" enum="VRSuppressedElement"
     expires_after="2020-07-01">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <owner>xr-dev@chromium.org</owner>
   <summary>
     We must suppress monocularly rendered ui elements in VR. This records which
@@ -181899,6 +182074,9 @@
 
 <histogram name="VR.Shell.EncounteredUnsupportedMode" enum="VRUnsupportedMode"
     expires_after="M85">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <owner>vollick@chromium.org</owner>
   <summary>
     We must exit VR mode when browsing in certain situations. This records which
@@ -181908,12 +182086,18 @@
 
 <histogram name="VR.VoiceSearch.EndState" enum="VRVoiceSearchEndState"
     expires_after="M85">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <owner>xr-dev@chromium.org</owner>
   <summary>The end state of a voice search request in VR.</summary>
 </histogram>
 
 <histogram name="VR.VoiceSearch.RecordAudioOsPermissionPromptChoice"
     enum="BooleanContinueChoice" expires_after="M85">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <owner>xr-dev@chromium.org</owner>
   <summary>
     Chrome shows a prompt when the OS's record audio permission is needed for
@@ -181957,6 +182141,9 @@
 
 <histogram name="VRRuntimeVersion" units="normalized version"
     expires_after="2020-07-01">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <owner>alcooper@chromium.org</owner>
   <owner>xr-dev@chromium.org</owner>
   <summary>The version of the runtime being used for VR.</summary>
@@ -190794,6 +190981,9 @@
 
 <histogram name="XR.WebXR.ConsentFlow" enum="XRSessionRequestDialogAction"
     expires_after="2020-07-01">
+  <obsolete>
+    Removed as of 06/2020.
+  </obsolete>
   <owner>alcooper@chromium.org</owner>
   <owner>mlamouri@chromium.org</owner>
   <owner>xr-dev@chromium.org</owner>
@@ -190805,6 +190995,9 @@
 
 <histogram name="XR.WebXR.ConsentFlowDuration.ConsentFlowAborted" units="ms"
     expires_after="2020-07-01">
+  <obsolete>
+    Removed as of 06/2020.
+  </obsolete>
   <owner>alcooper@chromium.org</owner>
   <owner>mlamouri@chromium.org</owner>
   <owner>xr-dev@chromium.org</owner>
@@ -190816,6 +191009,9 @@
 
 <histogram name="XR.WebXR.ConsentFlowDuration.ConsentGranted" units="ms"
     expires_after="2020-10-11">
+  <obsolete>
+    Removed as of 06/2020.
+  </obsolete>
   <owner>alcooper@chromium.org</owner>
   <owner>mlamouri@chromium.org</owner>
   <owner>xr-dev@chromium.org</owner>
@@ -190827,6 +191023,9 @@
 
 <histogram name="XR.WebXR.ConsentFlowDuration.ConsentNotGranted" units="ms"
     expires_after="2020-10-11">
+  <obsolete>
+    Removed as of 06/2020.
+  </obsolete>
   <owner>alcooper@chromium.org</owner>
   <owner>mlamouri@chromium.org</owner>
   <owner>xr-dev@chromium.org</owner>
@@ -209315,6 +209514,9 @@
 </histogram_suffixes>
 
 <histogram_suffixes name="VR.Mode" separator=".">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <suffix name="AllVR" label="Entered either VR Browsing or WebVR mode."/>
   <suffix name="VRBrowsing" label="Entered VR Browsing Mode."/>
   <suffix name="WebVRPresentation"
@@ -209332,6 +209534,9 @@
 </histogram_suffixes>
 
 <histogram_suffixes name="VRRuntimeVersionGVRHeadset" separator=".">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <suffix name="Cardboard" label="GVR version used with Carboard."/>
   <suffix name="Daydream" label="GVR version used with Daydream."/>
   <suffix name="Unknown" label="GVR version used with an unknown headset."/>
@@ -209339,6 +209544,9 @@
 </histogram_suffixes>
 
 <histogram_suffixes name="VRRuntimeVersionPlatform" separator=".">
+  <obsolete>
+    Removed 06/2020.
+  </obsolete>
   <suffix name="GVR"
       label="The GVR version being used for VR. Special values: (-4) Could
              not encode GVR version; (-3) Device does not support VR; (-2)
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index a86402c..dd4fcf6 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,16 +1,16 @@
 {
     "trace_processor_shell": {
         "win": {
-            "hash": "16c35e2101c4491c738dded9308b42799d9a7e61",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/7835859ea8de36fcb15ab8c0f31126fc9c6a3d0f/trace_processor_shell.exe"
+            "hash": "0d67e269f432323554f769f10344b2d196d483d9",
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/1c21759bb44e3f63dec4ec6b4cc078f4931fc13b/trace_processor_shell.exe"
         },
         "mac": {
             "hash": "cdcb1f5b233c5d3472a561a8f567d4927dec850b",
             "remote_path": "perfetto_binaries/trace_processor_shell/mac/058776deb61c3c6b1022c1e613e69518db32e443/trace_processor_shell"
         },
         "linux": {
-            "hash": "142d99a86f6119a9bbd831bbf2ad9748919bded6",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/7835859ea8de36fcb15ab8c0f31126fc9c6a3d0f/trace_processor_shell"
+            "hash": "4ed2ea0ca4a1d98f2ffb5381eb8254da6989c52f",
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/bc9475ac0bf57ff18e9fea4fc10b6e3eb8f09247/trace_processor_shell"
         }
     }
 }
\ No newline at end of file
diff --git a/ui/android/java/src/org/chromium/ui/base/Clipboard.java b/ui/android/java/src/org/chromium/ui/base/Clipboard.java
index 346314f..41d172ed 100644
--- a/ui/android/java/src/org/chromium/ui/base/Clipboard.java
+++ b/ui/android/java/src/org/chromium/ui/base/Clipboard.java
@@ -36,7 +36,6 @@
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.base.compat.ApiHelperForO;
 import org.chromium.base.metrics.RecordUserAction;
-import org.chromium.base.task.AsyncTask;
 import org.chromium.ui.R;
 import org.chromium.ui.widget.Toast;
 
@@ -278,8 +277,6 @@
 
     /**
      * Setting the clipboard's current primary clip to an image.
-     * This method requires background work and might not be immediately committed upon returning
-     * from this method.
      * @param Uri The {@link Uri} will become the content of the clipboard's primary clip.
      */
     public void setImageUri(final Uri uri) {
@@ -290,19 +287,9 @@
 
         grantUriPermission(uri);
 
-        // ClipData.newUri may access the disk (for reading mime types), and cause
-        // StrictModeDiskReadViolation if do it on UI thread.
-        new AsyncTask<ClipData>() {
-            @Override
-            protected ClipData doInBackground() {
-                return ClipData.newUri(
-                        ContextUtils.getApplicationContext().getContentResolver(), "image", uri);
-            }
-            @Override
-            protected void onPostExecute(ClipData clipData) {
-                setPrimaryClipNoException(clipData);
-            }
-        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+        ClipData clip = ClipData.newUri(
+                ContextUtils.getApplicationContext().getContentResolver(), "image", uri);
+        setPrimaryClipNoException(clip);
     }
 
     /**
diff --git a/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java b/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java
index d587886..525308b 100644
--- a/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java
+++ b/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java
@@ -72,12 +72,14 @@
      *                 false, return the path of the uncompressed WebView UI
      *                 strings instead. Note that APK .pak files are stored
      *                 compressed and handled differently.
+     * @param logError Logs if the file is not found.
      * @return Asset path to uncompressed .pak file, or null if the locale is
      *         not supported by this version of Chromium, or the file is
      *         missing.
      */
     @CalledByNative
-    private static String getLocalePakResourcePath(String locale, boolean inBundle) {
+    private static String getLocalePakResourcePath(
+            String locale, boolean inBundle, boolean logError) {
         if (sUncompressedLocales == null) {
             // Locales may be null in unit tests.
             return null;
@@ -103,8 +105,10 @@
         try (AssetFileDescriptor afd = manager.openNonAssetFd(assetPath)) {
             return assetPath;
         } catch (IOException e) {
-            Log.e(TAG, "Error while loading asset %s: %s", assetPath, e);
+            if (logError) {
+                Log.e(TAG, "path=%s", assetPath, e);
+            }
+            return null;
         }
-        return null;
     }
 }
diff --git a/ui/base/resource/resource_bundle_android.cc b/ui/base/resource/resource_bundle_android.cc
index b12c5366..1f251c4 100644
--- a/ui/base/resource/resource_bundle_android.cc
+++ b/ui/base/resource/resource_bundle_android.cc
@@ -59,11 +59,10 @@
 int LoadLocalePakFromApk(const std::string& app_locale,
                          bool in_split,
                          base::MemoryMappedFile::Region* out_region) {
+  bool log_error = true;
   std::string locale_path_within_apk =
-      GetPathForAndroidLocalePakWithinApk(app_locale, in_split);
+      GetPathForAndroidLocalePakWithinApk(app_locale, in_split, log_error);
   if (locale_path_within_apk.empty()) {
-    LOG(WARNING) << "locale_path_within_apk.empty() for locale "
-                 << app_locale;
     return -1;
   }
   return base::android::OpenApkAsset(locale_path_within_apk, out_region);
@@ -98,10 +97,13 @@
 
 // static
 bool ResourceBundle::LocaleDataPakExists(const std::string& locale) {
-  if (g_locale_paks_in_apk) {
-    return !GetPathForAndroidLocalePakWithinApk(locale, false).empty();
+  bool log_error = false;
+  bool in_split = !g_locale_paks_in_apk;
+  if (!in_split) {
+    return !GetPathForAndroidLocalePakWithinApk(locale, in_split, log_error)
+                .empty();
   }
-  if (!GetPathForAndroidLocalePakWithinApk(locale, true).empty())
+  if (!GetPathForAndroidLocalePakWithinApk(locale, in_split, log_error).empty())
     return true;
   const auto path = GetLocaleFilePath(locale);
   return !path.empty() && base::PathExists(path);
@@ -267,11 +269,13 @@
 }
 
 std::string GetPathForAndroidLocalePakWithinApk(const std::string& locale,
-                                                bool in_bundle) {
+                                                bool in_bundle,
+                                                bool log_error) {
   JNIEnv* env = base::android::AttachCurrentThread();
   base::android::ScopedJavaLocalRef<jstring> ret =
       Java_ResourceBundle_getLocalePakResourcePath(
-          env, base::android::ConvertUTF8ToJavaString(env, locale), in_bundle);
+          env, base::android::ConvertUTF8ToJavaString(env, locale), in_bundle,
+          log_error);
   if (ret.obj() == nullptr) {
     return std::string();
   }
diff --git a/ui/base/resource/resource_bundle_android.h b/ui/base/resource/resource_bundle_android.h
index 613a831..9909688 100644
--- a/ui/base/resource/resource_bundle_android.h
+++ b/ui/base/resource/resource_bundle_android.h
@@ -48,12 +48,14 @@
 // Returns the path within the apk for the given locale's .pak file, or an
 // empty string if it doesn't exist.
 // Only locale paks for the active Android language can be retrieved.
-// If |inSplit| is true, look into bundle split-specific location (e.g.
+// If |in_split| is true, look into bundle split-specific location (e.g.
 // 'assets/locales#lang_<lang>/<locale>.pak', otherwise use the default
 // WebView-related location, i.e. 'assets/stored-locales/<locale>.pak'.
+// If |log_error|, logs the path to logcat, but does not abort.
 COMPONENT_EXPORT(UI_BASE)
 std::string GetPathForAndroidLocalePakWithinApk(const std::string& locale,
-                                                bool in_split = false);
+                                                bool in_split,
+                                                bool log_error);
 
 // Called in test when there are no locale pak files available.
 COMPONENT_EXPORT(UI_BASE) void SetNoAvailableLocalePaksForTest();
diff --git a/ui/base/x/x11_drag_drop_client.cc b/ui/base/x/x11_drag_drop_client.cc
index 086ba14..0ec2c21 100644
--- a/ui/base/x/x11_drag_drop_client.cc
+++ b/ui/base/x/x11_drag_drop_client.cc
@@ -234,24 +234,24 @@
   // Find the current window the cursor is over.
   XID dest_window = FindWindowFor(screen_point);
 
-  if (source_current_window_ != dest_window) {
-    if (source_current_window_ != x11::None)
-      SendXdndLeave(source_current_window_);
+  if (target_current_window_ != dest_window) {
+    if (target_current_window_ != x11::None)
+      SendXdndLeave(target_current_window_);
 
-    source_current_window_ = dest_window;
+    target_current_window_ = dest_window;
     waiting_on_status_ = false;
     next_position_message_.reset();
     status_received_since_enter_ = false;
     negotiated_operation_ = DragDropTypes::DRAG_NONE;
 
-    if (source_current_window_ != x11::None) {
+    if (target_current_window_ != x11::None) {
       std::vector<x11::Atom> targets;
       source_provider_->RetrieveTargets(&targets);
-      SendXdndEnter(source_current_window_, targets);
+      SendXdndEnter(target_current_window_, targets);
     }
   }
 
-  if (source_current_window_ != x11::None) {
+  if (target_current_window_ != x11::None) {
     if (waiting_on_status_) {
       next_position_message_ =
           std::make_unique<std::pair<gfx::Point, unsigned long>>(screen_point,
@@ -346,7 +346,7 @@
 
   XID source_window = event.data.l[0];
 
-  if (source_window != source_current_window_)
+  if (source_window != target_current_window_)
     return;
 
   if (source_state_ != SourceState::kPendingDrop &&
@@ -417,16 +417,16 @@
 void XDragDropClient::OnXdndFinished(const XClientMessageEvent& event) {
   DVLOG(1) << "OnXdndFinished";
   XID source_window = event.data.l[0];
-  if (source_current_window_ != source_window)
+  if (target_current_window_ != source_window)
     return;
 
   // Clear |negotiated_operation_| if the drag was rejected.
   if ((event.data.l[1] & 1) == 0)
     negotiated_operation_ = DragDropTypes::DRAG_NONE;
 
-  // Clear |source_current_window_| to avoid sending XdndLeave upon ending the
+  // Clear |target_current_window_| to avoid sending XdndLeave upon ending the
   // move loop.
-  source_current_window_ = x11::None;
+  target_current_window_ = x11::None;
   EndMoveLoop();
 }
 
@@ -441,7 +441,7 @@
 }
 
 void XDragDropClient::InitDrag(int operation, const OSExchangeData* data) {
-  source_current_window_ = x11::None;
+  target_current_window_ = x11::None;
   source_state_ = SourceState::kOther;
   waiting_on_status_ = false;
   next_position_message_.reset();
@@ -517,7 +517,7 @@
     return;
   }
 
-  if (source_current_window_ != x11::None) {
+  if (target_current_window_ != x11::None) {
     if (waiting_on_status_) {
       if (status_received_since_enter_) {
         // If we are waiting for an XdndStatus message, we need to wait for it
@@ -544,8 +544,12 @@
 
       // We have negotiated an action with the other end.
       source_state_ = SourceState::kDropped;
-      SendXdndDrop(source_current_window_);
+      SendXdndDrop(target_current_window_);
       return;
+    } else {
+      // No transfer is negotiated.  We need to tell the target window that we
+      // are leaving.
+      SendXdndLeave(target_current_window_);
     }
   }
 
@@ -553,9 +557,9 @@
 }
 
 void XDragDropClient::HandleMoveLoopEnded() {
-  if (source_current_window_ != x11::None) {
-    SendXdndLeave(source_current_window_);
-    source_current_window_ = x11::None;
+  if (target_current_window_ != x11::None) {
+    SendXdndLeave(target_current_window_);
+    target_current_window_ = x11::None;
   }
   ResetDragContext();
   StopRepeatMouseMoveTimer();
diff --git a/ui/base/x/x11_drag_drop_client.h b/ui/base/x/x11_drag_drop_client.h
index 4f73c683..a0e5cc032d 100644
--- a/ui/base/x/x11_drag_drop_client.h
+++ b/ui/base/x/x11_drag_drop_client.h
@@ -199,10 +199,10 @@
   const XID xwindow_;
 
   // Target side information.
+  XID target_current_window_ = x11::None;
   std::unique_ptr<XDragContext> target_current_context_;
 
   // Source side information.
-  XID source_current_window_ = x11::None;
   SourceState source_state_ = SourceState::kOther;
   const XOSExchangeDataProvider* source_provider_ = nullptr;
 
diff --git a/ui/chromeos/translations/ui_chromeos_strings_cs.xtb b/ui/chromeos/translations/ui_chromeos_strings_cs.xtb
index 8bd6e5c3..5b9b54557 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_cs.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_cs.xtb
@@ -164,6 +164,7 @@
 <translation id="2924296707677495905">Přepis (namaskaram → ನಮಸ್ಕಾರ)</translation>
 <translation id="2925966894897775835">Tabulky</translation>
 <translation id="2938685643439809023">mongolština</translation>
+<translation id="2939410873710774399">Pokud soubory chcete otevřít pomocí aplikace <ph name="APP_NAME" /> (<ph name="VM_SOFTWARE_NAME" />), nejdříve je přesuňte do složky <ph name="FOLDER_NAME" />.</translation>
 <translation id="2942290791863759244">Německá klávesnice NEO 2</translation>
 <translation id="2943400156390503548">Prezentace</translation>
 <translation id="2943503720238418293">Použijte kratší název</translation>
@@ -324,6 +325,7 @@
 <translation id="4839847978919684242">Vybrané položky: <ph name="SELCTED_FILES_COUNT" /></translation>
 <translation id="4850886885716139402">Zobrazit</translation>
 <translation id="485316830061041779">němčina</translation>
+<translation id="4859297381873413734">Pokud soubory chcete otevřít pomocí aplikace <ph name="APP_NAME" /> (<ph name="VM_SOFTWARE_NAME" />), nejdříve je přesuňte do složky <ph name="FOLDER_NAME" />.</translation>
 <translation id="4867079195717347957">Kliknutím sloupec seřadíte sestupně.</translation>
 <translation id="4873265419374180291"><ph name="NUMBER_OF_BYTES" /> B</translation>
 <translation id="4880214202172289027">Posuvník hlasitosti</translation>
diff --git a/ui/chromeos/translations/ui_chromeos_strings_fil.xtb b/ui/chromeos/translations/ui_chromeos_strings_fil.xtb
index 1ef4c75..f02998f 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_fil.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_fil.xtb
@@ -164,6 +164,7 @@
 <translation id="2924296707677495905">Transliteration (namaskaram → ನಮಸ್ಕಾರ)</translation>
 <translation id="2925966894897775835">Sheets</translation>
 <translation id="2938685643439809023">Mongolian</translation>
+<translation id="2939410873710774399">Para makapagbukas ng mga file gamit ang <ph name="APP_NAME" /> (<ph name="VM_SOFTWARE_NAME" />), ilipat muna ang mga ito sa folder na <ph name="FOLDER_NAME" />.</translation>
 <translation id="2942290791863759244">German NEO 2 keyboard</translation>
 <translation id="2943400156390503548">Slides</translation>
 <translation id="2943503720238418293">Gumamit ng mas maikling pangalan</translation>
@@ -324,6 +325,7 @@
 <translation id="4839847978919684242"><ph name="SELCTED_FILES_COUNT" /> (na) item ang pinili</translation>
 <translation id="4850886885716139402">View</translation>
 <translation id="485316830061041779">German</translation>
+<translation id="4859297381873413734">Para makapagbukas ng mga file gamit ang <ph name="APP_NAME" /> (<ph name="VM_SOFTWARE_NAME" />), kopyahin muna ang mga ito sa folder na <ph name="FOLDER_NAME" />.</translation>
 <translation id="4867079195717347957">I-click para pagbukud-bukurin ang column sa pababang pagkakasunud-sunod.</translation>
 <translation id="4873265419374180291"><ph name="NUMBER_OF_BYTES" /> bytes</translation>
 <translation id="4880214202172289027">Slider ng volume</translation>
diff --git a/ui/chromeos/translations/ui_chromeos_strings_fr-CA.xtb b/ui/chromeos/translations/ui_chromeos_strings_fr-CA.xtb
index fddc793..8240246 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_fr-CA.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_fr-CA.xtb
@@ -164,6 +164,7 @@
 <translation id="2924296707677495905">Translittération (namaskaram → ನಮಸ್ಕಾರ)</translation>
 <translation id="2925966894897775835">Feuilles de calcul</translation>
 <translation id="2938685643439809023">Mongol</translation>
+<translation id="2939410873710774399">Pour ouvrir des fichiers avec <ph name="APP_NAME" /> (<ph name="VM_SOFTWARE_NAME" />), déplacez-les d'abord dans le dossier <ph name="FOLDER_NAME" />.</translation>
 <translation id="2942290791863759244">Clavier allemand NEO 2</translation>
 <translation id="2943400156390503548">Présentations</translation>
 <translation id="2943503720238418293">Utilisez un nom plus court</translation>
@@ -324,6 +325,7 @@
 <translation id="4839847978919684242"><ph name="SELCTED_FILES_COUNT" /> éléments sélectionnés</translation>
 <translation id="4850886885716139402">Affichage</translation>
 <translation id="485316830061041779">Allemand</translation>
+<translation id="4859297381873413734">Pour ouvrir des fichiers avec <ph name="APP_NAME" /> (<ph name="VM_SOFTWARE_NAME" />), copiez-les d'abord dans le dossier <ph name="FOLDER_NAME" />.</translation>
 <translation id="4867079195717347957">Cliquez ici pour trier la colonne par ordre décroissant.</translation>
 <translation id="4873265419374180291"><ph name="NUMBER_OF_BYTES" /> octets</translation>
 <translation id="4880214202172289027">Curseur de volume</translation>
diff --git a/ui/chromeos/translations/ui_chromeos_strings_ja.xtb b/ui/chromeos/translations/ui_chromeos_strings_ja.xtb
index 046a690..9c59ed80 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_ja.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_ja.xtb
@@ -164,6 +164,7 @@
 <translation id="2924296707677495905">文字変換(namaskaram → ನಮಸ್ಕಾರ)</translation>
 <translation id="2925966894897775835">スプレッドシート</translation>
 <translation id="2938685643439809023">モンゴル語</translation>
+<translation id="2939410873710774399"><ph name="APP_NAME" />(<ph name="VM_SOFTWARE_NAME" />)でファイルを開くには、<ph name="FOLDER_NAME" /> フォルダにファイルを移動してください。</translation>
 <translation id="2942290791863759244">ドイツ語(NEO 2)キーボード</translation>
 <translation id="2943400156390503548">スライド</translation>
 <translation id="2943503720238418293">もう少し短い名前にしてください</translation>
@@ -324,6 +325,7 @@
 <translation id="4839847978919684242"><ph name="SELCTED_FILES_COUNT" /> 個のアイテムを選択</translation>
 <translation id="4850886885716139402">表示</translation>
 <translation id="485316830061041779">ドイツ語</translation>
+<translation id="4859297381873413734"><ph name="APP_NAME" />(<ph name="VM_SOFTWARE_NAME" />)でファイルを開くには、<ph name="FOLDER_NAME" /> フォルダにファイルをコピーしてください。</translation>
 <translation id="4867079195717347957">クリックすると、列が降順で並べ替えられます。</translation>
 <translation id="4873265419374180291"><ph name="NUMBER_OF_BYTES" /> バイト</translation>
 <translation id="4880214202172289027">音量スライダー</translation>
diff --git a/ui/chromeos/translations/ui_chromeos_strings_sq.xtb b/ui/chromeos/translations/ui_chromeos_strings_sq.xtb
index 36acdaa..b59ab9d 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_sq.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_sq.xtb
@@ -164,6 +164,7 @@
 <translation id="2924296707677495905">Transliterim (namaskaram → ನಮಸ್ಕಾರ)</translation>
 <translation id="2925966894897775835">Fletët</translation>
 <translation id="2938685643439809023">Mongolisht</translation>
+<translation id="2939410873710774399">Për të hapur skedarët me <ph name="APP_NAME" /> (<ph name="VM_SOFTWARE_NAME" />), në fillim zhvendosi në dosjen <ph name="FOLDER_NAME" />.</translation>
 <translation id="2942290791863759244">Tastiera në gjermanisht NEO 2</translation>
 <translation id="2943400156390503548">Diapozitivat</translation>
 <translation id="2943503720238418293">Përdor një emër më të shkurtër</translation>
@@ -324,6 +325,7 @@
 <translation id="4839847978919684242">U zgjodhën <ph name="SELCTED_FILES_COUNT" /> artikuj</translation>
 <translation id="4850886885716139402">Pamja</translation>
 <translation id="485316830061041779">Gjermanisht</translation>
+<translation id="4859297381873413734">Për të hapur skedarët me <ph name="APP_NAME" /> (<ph name="VM_SOFTWARE_NAME" />), në fillim kopjoji në dosjen <ph name="FOLDER_NAME" />.</translation>
 <translation id="4867079195717347957">Kliko për të renditur kolonën në rend zbritës.</translation>
 <translation id="4873265419374180291"><ph name="NUMBER_OF_BYTES" /> bajtë</translation>
 <translation id="4880214202172289027">Rrëshqitësi i volumit</translation>
diff --git a/ui/chromeos/translations/ui_chromeos_strings_sw.xtb b/ui/chromeos/translations/ui_chromeos_strings_sw.xtb
index c69bc48..f04561d 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_sw.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_sw.xtb
@@ -164,6 +164,7 @@
 <translation id="2924296707677495905">Unukuzi wa mfumo wa kuandika (namaskaram → ನಮಸ್ಕಾರ)</translation>
 <translation id="2925966894897775835">Majedwali</translation>
 <translation id="2938685643439809023">Kimongolia</translation>
+<translation id="2939410873710774399">Ili ufungue faili ukitumia <ph name="APP_NAME" /> (<ph name="VM_SOFTWARE_NAME" />), zihamishie kwanza kwenye folda ya <ph name="FOLDER_NAME" />.</translation>
 <translation id="2942290791863759244">Kibodi ya Kijerumani NEO 2</translation>
 <translation id="2943400156390503548">Slaidi</translation>
 <translation id="2943503720238418293">Tumia jina fupi</translation>
@@ -324,6 +325,7 @@
 <translation id="4839847978919684242">Vifaa <ph name="SELCTED_FILES_COUNT" /> vilivyochaguliwa</translation>
 <translation id="4850886885716139402">Mwonekano</translation>
 <translation id="485316830061041779">Kijerumani</translation>
+<translation id="4859297381873413734">Ili ufungue faili ukitumia <ph name="APP_NAME" /> (<ph name="VM_SOFTWARE_NAME" />), zinakili kwanza kwenye folda ya <ph name="FOLDER_NAME" />.</translation>
 <translation id="4867079195717347957">Bofya ili upange safu wima katika mpangilio wa kushuka.</translation>
 <translation id="4873265419374180291">Baiti <ph name="NUMBER_OF_BYTES" /></translation>
 <translation id="4880214202172289027">Kitelezi cha sauti</translation>
diff --git a/ui/chromeos/translations/ui_chromeos_strings_th.xtb b/ui/chromeos/translations/ui_chromeos_strings_th.xtb
index d3d85eb0..f1219ae 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_th.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_th.xtb
@@ -164,6 +164,7 @@
 <translation id="2924296707677495905">การทับศัพท์ (namaskaram → ನಮಸ್ಕಾರ)</translation>
 <translation id="2925966894897775835">แผ่นงาน</translation>
 <translation id="2938685643439809023">มองโกเลีย</translation>
+<translation id="2939410873710774399">หากต้องการเปิดไฟล์ด้วย <ph name="APP_NAME" /> (<ph name="VM_SOFTWARE_NAME" />) ให้ย้ายไปที่โฟลเดอร์ <ph name="FOLDER_NAME" /> ก่อน</translation>
 <translation id="2942290791863759244">แป้นพิมพ์ NEO 2 ภาษาเยอรมัน</translation>
 <translation id="2943400156390503548">สไลด์</translation>
 <translation id="2943503720238418293">ใช้ชื่อที่สั้นลง</translation>
@@ -324,6 +325,7 @@
 <translation id="4839847978919684242">เลือก <ph name="SELCTED_FILES_COUNT" /> รายการ</translation>
 <translation id="4850886885716139402">มุมมอง</translation>
 <translation id="485316830061041779">เยอรมัน</translation>
+<translation id="4859297381873413734">หากต้องการเปิดไฟล์ด้วย <ph name="APP_NAME" /> (<ph name="VM_SOFTWARE_NAME" />) ให้คัดลอกไปที่โฟลเดอร์ <ph name="FOLDER_NAME" /> ก่อน</translation>
 <translation id="4867079195717347957">คลิกเพื่อจัดเรียงคอลัมน์จากมากไปหาน้อย</translation>
 <translation id="4873265419374180291"><ph name="NUMBER_OF_BYTES" /> ไบต์</translation>
 <translation id="4880214202172289027">แถบเลื่อนระดับเสียง</translation>
diff --git a/ui/chromeos/translations/ui_chromeos_strings_zu.xtb b/ui/chromeos/translations/ui_chromeos_strings_zu.xtb
index e60255c..aa49ddaa 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_zu.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_zu.xtb
@@ -164,6 +164,7 @@
 <translation id="2924296707677495905">Ukuguqula amagama (namaskaram → ನಮಸ್ಕಾರ)</translation>
 <translation id="2925966894897775835">Amashidi</translation>
 <translation id="2938685643439809023">Isi-Mongolian</translation>
+<translation id="2939410873710774399">Ukuze uvule amafayela nge-<ph name="APP_NAME" /> (<ph name="VM_SOFTWARE_NAME" />), qala ngokuwahambisa kufolda ye-<ph name="FOLDER_NAME" />.</translation>
 <translation id="2942290791863759244">Ikhibhodi ye-German NEO 2</translation>
 <translation id="2943400156390503548">Amaslayidi</translation>
 <translation id="2943503720238418293">Sebenzisa igama elifushane</translation>
@@ -324,6 +325,7 @@
 <translation id="4839847978919684242"><ph name="SELCTED_FILES_COUNT" /> izinto ezikhethiwe</translation>
 <translation id="4850886885716139402">Buka</translation>
 <translation id="485316830061041779">Isi-German</translation>
+<translation id="4859297381873413734">Ukuze uvule amafayela nge-<ph name="APP_NAME" /> (<ph name="VM_SOFTWARE_NAME" />), qala ngokuwakopishela kufolda ye-<ph name="FOLDER_NAME" />.</translation>
 <translation id="4867079195717347957">Chofoza ukuze uhlunge ikholomu ngendlela eyehlayo.</translation>
 <translation id="4873265419374180291"><ph name="NUMBER_OF_BYTES" /> bytes</translation>
 <translation id="4880214202172289027">Isilayida sevolumu</translation>
diff --git a/ui/file_manager/externs/volume_manager.js b/ui/file_manager/externs/volume_manager.js
index 3db0b850..78945ed 100644
--- a/ui/file_manager/externs/volume_manager.js
+++ b/ui/file_manager/externs/volume_manager.js
@@ -71,7 +71,7 @@
    *
    * @param {!Entry|!FilesAppEntry} entry File or directory entry. It
    *     can be a fake entry.
-   * @return {EntryLocation} Location information.
+   * @return {?EntryLocation} Location information.
    */
   getLocationInfo(entry) {}
 
diff --git a/ui/file_manager/file_manager/foreground/js/BUILD.gn b/ui/file_manager/file_manager/foreground/js/BUILD.gn
index 7034a21..4d2ba0e8 100644
--- a/ui/file_manager/file_manager/foreground/js/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -413,6 +413,7 @@
 js_library("file_tasks") {
   deps = [
     ":directory_model",
+    ":file_transfer_controller",
     ":naming_controller",
     ":task_history",
     "metadata:metadata_model",
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index 464540d..a386689 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -619,6 +619,10 @@
         this.appStateController_, this.taskController_);
 
     this.initDataTransferOperations_();
+    fileListPromise.then(() => {
+      this.taskController_.setFileTransferController(
+          this.fileTransferController_);
+    });
 
     this.selectionHandler_.onFileSelectionChanged();
     this.ui_.listContainer.endBatchUpdates();
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks.js b/ui/file_manager/file_manager/foreground/js/file_tasks.js
index f512dc5..1d0d0a0 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks.js
@@ -12,6 +12,7 @@
    * @param {!MetadataModel} metadataModel
    * @param {!DirectoryModel} directoryModel
    * @param {!FileManagerUI} ui
+   * @param {?FileTransferController} fileTransferController
    * @param {!Array<!Entry>} entries
    * @param {!Array<?string>} mimeTypes
    * @param {!Array<!chrome.fileManagerPrivate.FileTask>} tasks
@@ -22,9 +23,9 @@
    * @param {!ProgressCenter} progressCenter
    */
   constructor(
-      volumeManager, metadataModel, directoryModel, ui, entries, mimeTypes,
-      tasks, defaultTask, taskHistory, namingController, crostini,
-      progressCenter) {
+      volumeManager, metadataModel, directoryModel, ui, fileTransferController,
+      entries, mimeTypes, tasks, defaultTask, taskHistory, namingController,
+      crostini, progressCenter) {
     /** @private @const {!VolumeManager} */
     this.volumeManager_ = volumeManager;
 
@@ -37,6 +38,9 @@
     /** @private @const {!FileManagerUI} */
     this.ui_ = ui;
 
+    /** @private @const {?FileTransferController} */
+    this.fileTransferController_ = fileTransferController;
+
     /** @private @const {!Array<!Entry>} */
     this.entries_ = entries;
 
@@ -77,6 +81,7 @@
    * @param {!MetadataModel} metadataModel
    * @param {!DirectoryModel} directoryModel
    * @param {!FileManagerUI} ui
+   * @param {?FileTransferController} fileTransferController
    * @param {!Array<!Entry>} entries
    * @param {!Array<?string>} mimeTypes
    * @param {!TaskHistory} taskHistory
@@ -86,8 +91,9 @@
    * @return {!Promise<!FileTasks>}
    */
   static async create(
-      volumeManager, metadataModel, directoryModel, ui, entries, mimeTypes,
-      taskHistory, namingController, crostini, progressCenter) {
+      volumeManager, metadataModel, directoryModel, ui, fileTransferController,
+      entries, mimeTypes, taskHistory, namingController, crostini,
+      progressCenter) {
     let tasks = [];
 
     // getFileTasks supports only native entries.
@@ -134,9 +140,9 @@
     const defaultTask = FileTasks.getDefaultTask(tasks, taskHistory);
 
     return new FileTasks(
-        volumeManager, metadataModel, directoryModel, ui, entries, mimeTypes,
-        tasks, defaultTask, taskHistory, namingController, crostini,
-        progressCenter);
+        volumeManager, metadataModel, directoryModel, ui,
+        fileTransferController, entries, mimeTypes, tasks, defaultTask,
+        taskHistory, namingController, crostini, progressCenter);
   }
 
   /**
@@ -475,8 +481,9 @@
    * @return {boolean} True if the entry is from crostini.
    */
   static isCrostiniEntry(entry, volumeManager) {
-    return volumeManager.getLocationInfo(entry).rootType ===
-        VolumeManagerCommon.RootType.CROSTINI;
+    const location = volumeManager.getLocationInfo(entry);
+    return !!location &&
+        location.rootType === VolumeManagerCommon.RootType.CROSTINI;
   }
 
   /**
@@ -573,7 +580,8 @@
             FileTasks
                 .create(
                     this.volumeManager_, this.metadataModel_,
-                    this.directoryModel_, this.ui_, this.entries_,
+                    this.directoryModel_, this.ui_,
+                    this.fileTransferController_, this.entries_,
                     this.mimeTypes_, this.taskHistory_, this.namingController_,
                     this.crostini_, this.progressCenter_)
                 .then(
@@ -650,7 +658,7 @@
   executeInternal_(task) {
     const onFileManagerPrivateExecuteTask = result => {
       if (chrome.runtime.lastError) {
-        console.warn(
+        console.error(
             'Unable to execute task: ' + chrome.runtime.lastError.message);
         return;
       }
@@ -665,17 +673,42 @@
           break;
         case taskResult.FAILED_PLUGIN_VM_TASK_DIRECTORY_NOT_SHARED:
         case taskResult.FAILED_PLUGIN_VM_TASK_EXTERNAL_DRIVE:
-          const messageId =
+          const [messageId, buttonId, toMove] =
               result == taskResult.FAILED_PLUGIN_VM_TASK_DIRECTORY_NOT_SHARED ?
-              'UNABLE_TO_OPEN_WITH_PLUGIN_VM_DIRECTORY_NOT_SHARED_MESSAGE' :
-              'UNABLE_TO_OPEN_WITH_PLUGIN_VM_EXTERNAL_DRIVE_MESSAGE';
-          this.ui_.alertDialog.showHtml(
+              [
+                'UNABLE_TO_OPEN_WITH_PLUGIN_VM_DIRECTORY_NOT_SHARED_MESSAGE',
+                'CONFIRM_MOVE_BUTTON_LABEL',
+                true,
+              ] :
+              [
+                'UNABLE_TO_OPEN_WITH_PLUGIN_VM_EXTERNAL_DRIVE_MESSAGE',
+                'CONFIRM_COPY_BUTTON_LABEL',
+                false,
+              ];
+          const dialog = new FilesConfirmDialog(this.ui_.element);
+          dialog.setOkLabel(strf(buttonId));
+          dialog.showHtml(
               strf(
                   'UNABLE_TO_OPEN_WITH_PLUGIN_VM_TITLE',
                   strf('PLUGIN_VM_APP_NAME')),
               strf(
                   messageId, task.title, strf('PLUGIN_VM_APP_NAME'),
-                  strf('PLUGIN_VM_DIRECTORY_LABEL')));
+                  strf('PLUGIN_VM_DIRECTORY_LABEL')),
+              async () => {
+                if (!this.fileTransferController_) {
+                  console.error('FileTransferController not set');
+                  return;
+                }
+
+                const pvmDir = await this.getPvmSharedDir_();
+
+                this.fileTransferController_.executePaste(
+                    new FileTransferController.PastePlan(
+                        this.entries_.map(e => e.toURL()), pvmDir,
+                        assert(this.volumeManager_.getLocationInfo(pvmDir)),
+                        toMove));
+                this.directoryModel_.changeDirectoryEntry(pvmDir);
+              });
           break;
       }
     };
@@ -1175,6 +1208,21 @@
 
     return null;
   }
+
+  async getPvmSharedDir_() {
+    return new Promise((resolve, reject) => {
+      this.volumeManager_
+          .getCurrentProfileVolumeInfo(VolumeManagerCommon.VolumeType.DOWNLOADS)
+          .fileSystem.root.getDirectory(
+              'PvmDefault', {create: false},
+              (dir) => {
+                resolve(dir);
+              },
+              (...args) => {
+                reject(new Error(`Error getting PvmDefault dir: ${args}`));
+              });
+    });
+  }
 }
 
 /**
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
index a0d773d..c997a6a 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
@@ -58,6 +58,12 @@
   recordTaskExecuted: function(id) {},
 });
 
+/**
+ * Mock file transfer controller.
+ * @type {!FileTransferController}
+ */
+const mockFileTransferController = /** @type {!FileTransferController} */ ({});
+
 // Set up test components.
 function setUp() {
   // Mock LoadTimeData strings.
@@ -189,8 +195,9 @@
     FileTasks
         .create(
             fileManager.volumeManager, fileManager.metadataModel,
-            fileManager.directoryModel, fileManager.ui, entries, [null],
-            mockTaskHistory, fileManager.namingController, fileManager.crostini,
+            fileManager.directoryModel, fileManager.ui,
+            mockFileTransferController, entries, [null], mockTaskHistory,
+            fileManager.namingController, fileManager.crostini,
             fileManager.progressCenter)
         .then(tasks => {
           tasks.executeDefault();
@@ -217,8 +224,9 @@
     FileTasks
         .create(
             fileManager.volumeManager, fileManager.metadataModel,
-            fileManager.directoryModel, fileManager.ui, entries, mimeTypes,
-            mockTaskHistory, fileManager.namingController, fileManager.crostini,
+            fileManager.directoryModel, fileManager.ui,
+            mockFileTransferController, entries, mimeTypes, mockTaskHistory,
+            fileManager.namingController, fileManager.crostini,
             fileManager.progressCenter)
         .then(tasks => {
           tasks.executeDefault();
@@ -246,8 +254,9 @@
     FileTasks
         .create(
             fileManager.volumeManager, fileManager.metadataModel,
-            fileManager.directoryModel, fileManager.ui, entries, mimeTypes,
-            mockTaskHistory, fileManager.namingController, fileManager.crostini,
+            fileManager.directoryModel, fileManager.ui,
+            mockFileTransferController, entries, mimeTypes, mockTaskHistory,
+            fileManager.namingController, fileManager.crostini,
             fileManager.progressCenter)
         .then(tasks => {
           tasks.executeDefault();
@@ -273,8 +282,9 @@
     FileTasks
         .create(
             fileManager.volumeManager, fileManager.metadataModel,
-            fileManager.directoryModel, fileManager.ui, entries, [null],
-            mockTaskHistory, fileManager.namingController, fileManager.crostini,
+            fileManager.directoryModel, fileManager.ui,
+            mockFileTransferController, entries, [null], mockTaskHistory,
+            fileManager.namingController, fileManager.crostini,
             fileManager.progressCenter)
         .then(tasks => {
           tasks.executeDefault();
@@ -358,8 +368,8 @@
                 },
               },
             }),
-            [mockEntry], ['application/rtf'], mockTaskHistory,
-            fileManager.namingController, fileManager.crostini,
+            mockFileTransferController, [mockEntry], ['application/rtf'],
+            mockTaskHistory, fileManager.namingController, fileManager.crostini,
             fileManager.progressCenter)
         .then(tasks => {
           tasks.openSuggestAppsDialog(() => {}, () => {}, () => {});
@@ -382,8 +392,9 @@
     FileTasks
         .create(
             fileManager.volumeManager, fileManager.metadataModel,
-            fileManager.directoryModel, fileManager.ui, [mockEntry], [null],
-            mockTaskHistory, fileManager.namingController, fileManager.crostini,
+            fileManager.directoryModel, fileManager.ui,
+            mockFileTransferController, [mockEntry], [null], mockTaskHistory,
+            fileManager.namingController, fileManager.crostini,
             fileManager.progressCenter)
         .then(tasks => {
           tasks.openSuggestAppsDialog(() => {}, () => {}, resolve);
@@ -498,8 +509,9 @@
     FileTasks
         .create(
             fileManager.volumeManager, fileManager.metadataModel,
-            fileManager.directoryModel, fileManager.ui, [mockEntry], [null],
-            taskHistory, fileManager.namingController, fileManager.crostini,
+            fileManager.directoryModel, fileManager.ui,
+            mockFileTransferController, [mockEntry], [null], taskHistory,
+            fileManager.namingController, fileManager.crostini,
             fileManager.progressCenter)
         .then(tasks => {
           tasks.executeDefault();
@@ -562,8 +574,9 @@
     FileTasks
         .create(
             fileManager.volumeManager, fileManager.metadataModel,
-            fileManager.directoryModel, fileManager.ui, [mockEntry], [null],
-            taskHistory, fileManager.namingController, fileManager.crostini,
+            fileManager.directoryModel, fileManager.ui,
+            mockFileTransferController, [mockEntry], [null], taskHistory,
+            fileManager.namingController, fileManager.crostini,
             fileManager.progressCenter)
         .then(tasks => {
           tasks.executeDefault();
@@ -613,8 +626,9 @@
     FileTasks
         .create(
             fileManager.volumeManager, fileManager.metadataModel,
-            fileManager.directoryModel, fileManager.ui, [mockEntry], [null],
-            mockTaskHistory, fileManager.namingController, fileManager.crostini,
+            fileManager.directoryModel, fileManager.ui,
+            mockFileTransferController, [mockEntry], [null], mockTaskHistory,
+            fileManager.namingController, fileManager.crostini,
             fileManager.progressCenter)
         .then(tasks => {
           tasks.executeDefault();
@@ -728,8 +742,9 @@
 
   const tasks = await FileTasks.create(
       fileManager.volumeManager, fileManager.metadataModel,
-      fileManager.directoryModel, fileManager.ui, entries, ['application/jpg'],
-      mockTaskHistory, fileManager.namingController, fileManager.crostini,
+      fileManager.directoryModel, fileManager.ui, mockFileTransferController,
+      entries, ['application/jpg'], mockTaskHistory,
+      fileManager.namingController, fileManager.crostini,
       fileManager.progressCenter);
 
   const mockTask = /** @type {!chrome.fileManagerPrivate.FileTask} */ ({
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller.js b/ui/file_manager/file_manager/foreground/js/task_controller.js
index 5408af1..da1eba87 100644
--- a/ui/file_manager/file_manager/foreground/js/task_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/task_controller.js
@@ -37,6 +37,9 @@
      */
     this.ui_ = ui;
 
+    /** @private {?FileTransferController} */
+    this.fileTransferController_;
+
     /**
      * @private {!MetadataModel}
      * @const
@@ -173,6 +176,13 @@
   }
 
   /**
+   * @param {?FileTransferController} fileTransferController
+   */
+  setFileTransferController(fileTransferController) {
+    this.fileTransferController_ = fileTransferController;
+  }
+
+  /**
    * Task combobox handler.
    *
    * @param {Object} event Event containing task which was clicked.
@@ -400,9 +410,9 @@
       return FileTasks
           .create(
               this.volumeManager_, this.metadataModel_, this.directoryModel_,
-              this.ui_, selection.entries, assert(selection.mimeTypes),
-              this.taskHistory_, this.namingController_, this.crostini_,
-              this.progressCenter_)
+              this.ui_, this.fileTransferController_, selection.entries,
+              assert(selection.mimeTypes), this.taskHistory_,
+              this.namingController_, this.crostini_, this.progressCenter_)
           .then(tasks => {
             if (this.selectionHandler_.selection !== selection) {
               if (util.isSameEntries(this.tasksEntries_, selection.entries)) {
@@ -512,9 +522,9 @@
     return this.metadataModel_.get([entry], ['contentMimeType']).then(props => {
       return FileTasks.create(
           this.volumeManager_, this.metadataModel_, this.directoryModel_,
-          this.ui_, [entry], [props[0].contentMimeType || null],
-          this.taskHistory_, this.namingController_, this.crostini_,
-          this.progressCenter_);
+          this.ui_, this.fileTransferController_, [entry],
+          [props[0].contentMimeType || null], this.taskHistory_,
+          this.namingController_, this.crostini_, this.progressCenter_);
     });
   }
 
diff --git a/ui/file_manager/integration_tests/file_manager/crostini.js b/ui/file_manager/integration_tests/file_manager/crostini.js
index 1d3e5ab..227844b3 100644
--- a/ui/file_manager/integration_tests/file_manager/crostini.js
+++ b/ui/file_manager/integration_tests/file_manager/crostini.js
@@ -117,13 +117,16 @@
   await remoteCall.waitUntilTaskExecutes(
       appId, 'plugin-vm-app-id|pluginvm|open-with',
       ['failed_plugin_vm_task_directory_not_shared']);
-  await remoteCall.waitForElement(appId, '.files-alert-dialog:not([hidden])');
+  await remoteCall.waitForElement(
+      appId, '.cr-dialog-frame:not(#default-task-dialog):not([hidden])');
 
   // Validate error messages.
   const dialogTitles = await remoteCall.callRemoteTestUtil(
-      'queryAllElements', appId, ['.files-alert-dialog .cr-dialog-title']);
+      'queryAllElements', appId,
+      ['.cr-dialog-frame:not(#default-task-dialog) .cr-dialog-title']);
   const dialogTexts = await remoteCall.callRemoteTestUtil(
-      'queryAllElements', appId, ['.files-alert-dialog .cr-dialog-text']);
+      'queryAllElements', appId,
+      ['.cr-dialog-frame:not(#default-task-dialog) .cr-dialog-text']);
 
   chrome.test.assertEq(
       ['Unable to open with Plugin VM'], dialogTitles.map(el => el.text));
@@ -131,6 +134,9 @@
       ['To open files with Plugin VM App (Plugin VM), ' +
        'first move them to the Plugin VM folder.'],
       dialogTexts.map(el => el.text));
+
+  // TODO(crbug.com/1049453): Test file is moved. This can only be tested when
+  // tests allow creating /MyFiles/PvmDefault.
 };
 
 testcase.pluginVmFileOnExternalDriveErrorDialog = async () => {
@@ -178,13 +184,16 @@
   await remoteCall.waitUntilTaskExecutes(
       appId, 'plugin-vm-app-id|pluginvm|open-with',
       ['failed_plugin_vm_task_external_drive']);
-  await remoteCall.waitForElement(appId, '.files-alert-dialog:not([hidden])');
+  await remoteCall.waitForElement(
+      appId, '.cr-dialog-frame:not(#default-task-dialog):not([hidden])');
 
   // Validate error messages.
   const dialogTitles = await remoteCall.callRemoteTestUtil(
-      'queryAllElements', appId, ['.files-alert-dialog .cr-dialog-title']);
+      'queryAllElements', appId,
+      ['.cr-dialog-frame:not(#default-task-dialog) .cr-dialog-title']);
   const dialogTexts = await remoteCall.callRemoteTestUtil(
-      'queryAllElements', appId, ['.files-alert-dialog .cr-dialog-text']);
+      'queryAllElements', appId,
+      ['.cr-dialog-frame:not(#default-task-dialog) .cr-dialog-text']);
 
   chrome.test.assertEq(
       ['Unable to open with Plugin VM'], dialogTitles.map(el => el.text));
@@ -192,4 +201,7 @@
       ['To open files with Plugin VM App (Plugin VM), ' +
        'first copy them to the Plugin VM folder.'],
       dialogTexts.map(el => el.text));
+
+  // TODO(crbug.com/1049453): Test file is moved. This can only be tested when
+  // tests allow creating /MyFiles/PvmDefault.
 };
diff --git a/ui/file_manager/integration_tests/test_util.js b/ui/file_manager/integration_tests/test_util.js
index 1cc6efe..fcf4acf 100644
--- a/ui/file_manager/integration_tests/test_util.js
+++ b/ui/file_manager/integration_tests/test_util.js
@@ -1344,6 +1344,15 @@
     sizeText: '51 bytes',
     typeText: 'CRDOWNLOAD file'
   }),
+
+  pluginVm: new TestEntryInfo({
+    type: EntryType.DIRECTORY,
+    targetPath: 'PvmDefault',
+    lastModifiedTime: 'Jan 1, 1980, 11:59 PM',
+    nameText: 'Plugin VM',
+    sizeText: '--',
+    typeText: 'Folder'
+  }),
 };
 
 /**
diff --git a/ui/ozone/ozone.gni b/ui/ozone/ozone.gni
index 13fecf9..ca6e9dd 100644
--- a/ui/ozone/ozone.gni
+++ b/ui/ozone/ozone.gni
@@ -4,6 +4,7 @@
 
 import("//build/config/chromecast_build.gni")
 import("//build/config/ui.gni")
+import("//build/toolchain/kythe.gni")
 import("//build/toolchain/toolchain.gni")
 
 declare_args() {
@@ -46,6 +47,9 @@
     ozone_platform = "headless"
     ozone_platform_headless = true
 
+    # Enable the Ozone Wayland platform for codesearch-gen bots so we get cross-references in codesearch.
+    ozone_platform_wayland = enable_kythe_annotations
+
     if (is_cast_audio_only) {
       # Just use headless for audio-only Cast platforms.
     } else if (is_chromecast && !is_fuchsia) {
diff --git a/ui/ozone/platform/wayland/host/wayland_subsurface.cc b/ui/ozone/platform/wayland/host/wayland_subsurface.cc
index f088f66c..e76aa637 100644
--- a/ui/ozone/platform/wayland/host/wayland_subsurface.cc
+++ b/ui/ozone/platform/wayland/host/wayland_subsurface.cc
@@ -16,7 +16,7 @@
 
 gfx::Rect AdjustSubsurfaceBounds(const gfx::Rect& bounds_px,
                                  const gfx::Rect& parent_bounds_px,
-                                 int32_t ui_scale,
+                                 float ui_scale,
                                  int32_t buffer_scale) {
   const auto parent_bounds_dip =
       gfx::ScaleToRoundedRect(parent_bounds_px, 1.0 / ui_scale);
diff --git a/ui/ozone/platform/x11/x11_window_ozone.cc b/ui/ozone/platform/x11/x11_window_ozone.cc
index 66658dc..3f98795 100644
--- a/ui/ozone/platform/x11/x11_window_ozone.cc
+++ b/ui/ozone/platform/x11/x11_window_ozone.cc
@@ -47,6 +47,8 @@
 
   end_drag_callback_ = std::move(callback);
   drag_drop_client_->InitDrag(operation, &data);
+  drag_operation_ = 0;
+  notified_enter_ = false;
 
   SetCapture();
 
@@ -61,9 +63,23 @@
   WmDropHandler* drop_handler = GetWmDropHandler(*this);
   if (!drop_handler)
     return ui::DragDropTypes::DRAG_NONE;
-  // TODO: calculate the appropriate drag operation here.
-  return drop_handler->OnDragMotion(gfx::PointF(screen_point),
-                                    ui::DragDropTypes::DRAG_COPY);
+  if (!notified_enter_) {
+    DCHECK(drag_drop_client_);
+    auto* target_current_context = drag_drop_client_->target_current_context();
+    DCHECK(target_current_context);
+    drop_handler->OnDragEnter(
+        gfx::PointF(screen_point),
+        std::make_unique<ui::OSExchangeData>(
+            std::make_unique<ui::XOSExchangeDataProvider>(
+                drag_drop_client_->xwindow(),
+                target_current_context->fetched_targets())),
+        ui::DragDropTypes::DRAG_COPY);
+    notified_enter_ = true;
+  }
+
+  drag_operation_ = drop_handler->OnDragMotion(gfx::PointF(screen_point),
+                                               ui::DragDropTypes::DRAG_COPY);
+  return drag_operation_;
 }
 
 void X11WindowOzone::UpdateCursor(
@@ -80,7 +96,11 @@
 }
 
 void X11WindowOzone::OnBeforeDragLeave() {
-  NOTIMPLEMENTED_LOG_ONCE();
+  WmDropHandler* drop_handler = GetWmDropHandler(*this);
+  if (!drop_handler)
+    return;
+  drop_handler->OnDragLeave();
+  notified_enter_ = false;
 }
 
 int X11WindowOzone::PerformDrop() {
@@ -88,17 +108,13 @@
   if (!drop_handler)
     return ui::DragDropTypes::DRAG_NONE;
 
-  DCHECK(drag_drop_client_);
-  auto* target_current_context = drag_drop_client_->target_current_context();
-  DCHECK(target_current_context);
+  DCHECK(notified_enter_);
 
-  int drag_operation = ui::DragDropTypes::DRAG_NONE;
-
-  drop_handler->OnDragDrop(std::make_unique<ui::OSExchangeData>(
-      std::make_unique<ui::XOSExchangeDataProvider>(
-          drag_drop_client_->xwindow(),
-          target_current_context->fetched_targets())));
-  return drag_operation;
+  // The drop data has been supplied on entering the window.  The drop handler
+  // should have it since then.
+  drop_handler->OnDragDrop({});
+  notified_enter_ = false;
+  return drag_operation_;
 }
 
 void X11WindowOzone::EndMoveLoop() {
diff --git a/ui/ozone/platform/x11/x11_window_ozone.h b/ui/ozone/platform/x11/x11_window_ozone.h
index 3e2a83f..c7f8d311 100644
--- a/ui/ozone/platform/x11/x11_window_ozone.h
+++ b/ui/ozone/platform/x11/x11_window_ozone.h
@@ -56,6 +56,10 @@
 
   // True while the drag initiated in this window is in progress.
   bool dragging_ = false;
+  // Whether the drop handler has notified that the drag has entered.
+  bool notified_enter_ = false;
+  // Keeps the last negotiated operation returned by the drop handler.
+  int drag_operation_ = 0;
 
   std::unique_ptr<XDragDropClient> drag_drop_client_;
   base::OnceCallback<void(int)> end_drag_callback_;
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc b/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
index 0e70dad..51cc07f5 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
@@ -76,10 +76,12 @@
   aura::client::CursorClient* cursor_client =
       aura::client::GetCursorClient(root_window);
 
-  initial_cursor_ = source_window->GetHost()->last_cursor();
+  auto initial_cursor = source_window->GetHost()->last_cursor();
   drag_operation_ = operation;
-  cursor_client->SetCursor(
-      cursor_manager_->GetInitializedCursor(ui::mojom::CursorType::kGrabbing));
+  if (cursor_client) {
+    cursor_client->SetCursor(cursor_manager_->GetInitializedCursor(
+        ui::mojom::CursorType::kGrabbing));
+  }
 
   drag_handler_->StartDrag(
       *data.get(), operation, cursor_client->GetCursor(),
@@ -87,7 +89,10 @@
                      base::Unretained(this)));
   in_move_loop_ = true;
   run_loop.Run();
-  DragDropSessionCompleted();
+
+  if (cursor_client)
+    cursor_client->SetCursor(initial_cursor);
+
   return drag_operation_;
 }
 
@@ -116,15 +121,13 @@
   last_drag_point_ = point;
   drag_operation_ = operation;
 
-  // If it doesn't have |data|, it defers sending events to
-  // |drag_drop_delegate_|. It will try again before handling drop.
+  // If |data| is empty, we defer sending any events to the
+  // |drag_drop_delegate_|.  All necessary events will be sent on dropping.
   if (!data)
     return;
 
-  os_exchange_data_ = std::move(data);
-  std::unique_ptr<ui::DropTargetEvent> event = CreateDropTargetEvent(point);
-  if (drag_drop_delegate_ && event)
-    drag_drop_delegate_->OnDragEntered(*event);
+  data_to_drop_ = std::move(data);
+  UpdateTargetAndCreateDropEvent(point);
 }
 
 int DesktopDragDropClientOzone::OnDragMotion(const gfx::PointF& point,
@@ -134,10 +137,11 @@
   int client_operation =
       ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE;
 
-  if (os_exchange_data_) {
-    std::unique_ptr<ui::DropTargetEvent> event = CreateDropTargetEvent(point);
-    // If |os_exchange_data_| has a valid data, |drag_drop_delegate_| returns
-    // the operation which it expects.
+  // If |data_to_drop_| has a valid data, ask |drag_drop_delegate_| about the
+  // operation that it would accept.
+  if (data_to_drop_) {
+    std::unique_ptr<ui::DropTargetEvent> event =
+        UpdateTargetAndCreateDropEvent(point);
     if (drag_drop_delegate_ && event)
       client_operation = drag_drop_delegate_->OnDragUpdated(*event);
   }
@@ -146,47 +150,54 @@
 
 void DesktopDragDropClientOzone::OnDragDrop(
     std::unique_ptr<ui::OSExchangeData> data) {
-  // If it doesn't have |os_exchange_data_|, it needs to update it with |data|.
-  if (!os_exchange_data_) {
-    DCHECK(data);
-    os_exchange_data_ = std::move(data);
-    std::unique_ptr<ui::DropTargetEvent> event =
-        CreateDropTargetEvent(last_drag_point_);
-    // Sends the deferred drag events to |drag_drop_delegate_| before handling
-    // drop.
-    if (drag_drop_delegate_ && event) {
-      drag_drop_delegate_->OnDragEntered(*event);
-      // TODO(jkim): It doesn't use the return value from 'OnDragUpdated' and
-      // doesn't have a chance to update the expected operation.
-      // https://crbug.com/875164
+  // If we didn't have |data_to_drop_|, then |drag_drop_delegate_| had never
+  // been updated, and now it needs to receive deferred enter and update events
+  // before handling the actual drop.
+  const bool posponed_enter_and_update = !data_to_drop_;
+
+  // If we had |data_to_drop_| already since the drag had entered the window,
+  // then we don't expect new data to come now, and vice versa.
+  DCHECK((data_to_drop_ && !data) || (!data_to_drop_ && data));
+  if (!data_to_drop_)
+    data_to_drop_ = std::move(data);
+
+  // This will call the delegate's OnDragEntered if needed.
+  auto event = UpdateTargetAndCreateDropEvent(last_drag_point_);
+  if (drag_drop_delegate_ && event) {
+    if (posponed_enter_and_update) {
+      // TODO(https://crbug.com/1014860): deal with drop refusals.
+      // The delegate's OnDragUpdated returns an operation that the delegate
+      // would accept.  Normally the accepted operation would be propagated
+      // properly, and if the delegate didn't accept it, the drop would never
+      // be called, but in this scenario of postponed updates we send all events
+      // at once.  Now we just drop, but perhaps we could call OnDragLeave
+      // and quit?
       drag_drop_delegate_->OnDragUpdated(*event);
     }
-  } else {
-    // If it has |os_exchange_data_|, it doesn't expect |data| on OnDragDrop.
-    DCHECK(!data);
+    drag_operation_ =
+        drag_drop_delegate_->OnPerformDrop(*event, std::move(data_to_drop_));
   }
-  PerformDrop();
+  ResetDragDropTarget();
 }
 
 void DesktopDragDropClientOzone::OnDragLeave() {
-  os_exchange_data_.reset();
+  data_to_drop_.reset();
   ResetDragDropTarget();
 }
 
+void DesktopDragDropClientOzone::OnWindowDestroyed(aura::Window* window) {
+  DCHECK_EQ(window, current_window_);
+
+  current_window_->RemoveObserver(this);
+  current_window_ = nullptr;
+  drag_drop_delegate_ = nullptr;
+}
+
 void DesktopDragDropClientOzone::OnDragSessionClosed(int dnd_action) {
   drag_operation_ = dnd_action;
   QuitRunLoop();
 }
 
-void DesktopDragDropClientOzone::DragDropSessionCompleted() {
-  aura::client::CursorClient* cursor_client =
-      aura::client::GetCursorClient(root_window_);
-  if (!cursor_client)
-    return;
-
-  cursor_client->SetCursor(initial_cursor_);
-}
-
 void DesktopDragDropClientOzone::QuitRunLoop() {
   in_move_loop_ = false;
   if (quit_closure_.is_null())
@@ -195,50 +206,49 @@
 }
 
 std::unique_ptr<ui::DropTargetEvent>
-DesktopDragDropClientOzone::CreateDropTargetEvent(const gfx::PointF& location) {
+DesktopDragDropClientOzone::UpdateTargetAndCreateDropEvent(
+    const gfx::PointF& location) {
   const gfx::Point point(location.x(), location.y());
   aura::Window* window = GetTargetWindow(root_window_, point);
-  if (!window)
+  if (!window) {
+    ResetDragDropTarget();
+    return nullptr;
+  }
+
+  auto* new_delegate = aura::client::GetDragDropDelegate(window);
+  const bool delegate_has_changed = (new_delegate != drag_drop_delegate_);
+  if (delegate_has_changed) {
+    ResetDragDropTarget();
+    drag_drop_delegate_ = new_delegate;
+    current_window_ = window;
+    current_window_->AddObserver(this);
+  }
+
+  if (!drag_drop_delegate_)
     return nullptr;
 
-  UpdateDragDropDelegate(window);
   gfx::Point root_location(location.x(), location.y());
   root_window_->GetHost()->ConvertScreenInPixelsToDIP(&root_location);
   gfx::PointF target_location(root_location);
   aura::Window::ConvertPointToTarget(root_window_, window, &target_location);
 
-  return std::make_unique<ui::DropTargetEvent>(
-      *os_exchange_data_, target_location, gfx::PointF(root_location),
+  auto event = std::make_unique<ui::DropTargetEvent>(
+      *data_to_drop_, target_location, gfx::PointF(root_location),
       drag_operation_);
-}
-
-void DesktopDragDropClientOzone::UpdateDragDropDelegate(aura::Window* window) {
-  aura::client::DragDropDelegate* delegate =
-      aura::client::GetDragDropDelegate(window);
-
-  if (drag_drop_delegate_ == delegate)
-    return;
-
-  ResetDragDropTarget();
-  if (delegate)
-    drag_drop_delegate_ = delegate;
+  if (delegate_has_changed)
+    drag_drop_delegate_->OnDragEntered(*event);
+  return event;
 }
 
 void DesktopDragDropClientOzone::ResetDragDropTarget() {
-  if (!drag_drop_delegate_)
-    return;
-  drag_drop_delegate_->OnDragExited();
-  drag_drop_delegate_ = nullptr;
-}
-
-void DesktopDragDropClientOzone::PerformDrop() {
-  std::unique_ptr<ui::DropTargetEvent> event =
-      CreateDropTargetEvent(last_drag_point_);
-  if (drag_drop_delegate_ && event)
-    drag_operation_ = drag_drop_delegate_->OnPerformDrop(
-        *event, std::move(os_exchange_data_));
-  DragDropSessionCompleted();
-  ResetDragDropTarget();
+  if (drag_drop_delegate_) {
+    drag_drop_delegate_->OnDragExited();
+    drag_drop_delegate_ = nullptr;
+  }
+  if (current_window_) {
+    current_window_->RemoveObserver(this);
+    current_window_ = nullptr;
+  }
 }
 
 }  // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h b/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h
index 05b2fd2..44dc34e 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h
@@ -9,6 +9,7 @@
 
 #include "base/callback.h"
 #include "ui/aura/client/drag_drop_client.h"
+#include "ui/aura/window_observer.h"
 #include "ui/base/cursor/cursor.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/gfx/geometry/point_f.h"
@@ -32,14 +33,18 @@
 
 class VIEWS_EXPORT DesktopDragDropClientOzone
     : public aura::client::DragDropClient,
-      public ui::WmDropHandler {
+      public ui::WmDropHandler,
+      public aura::WindowObserver {
  public:
   DesktopDragDropClientOzone(aura::Window* root_window,
                              views::DesktopNativeCursorManager* cursor_manager,
                              ui::WmDragHandler* drag_handler);
   ~DesktopDragDropClientOzone() override;
 
-  // Overridden from aura::client::DragDropClient:
+ private:
+  friend class DesktopDragDropClientOzoneTest;
+
+  // aura::client::DragDropClient
   int StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,
                        aura::Window* root_window,
                        aura::Window* source_window,
@@ -51,7 +56,7 @@
   void AddObserver(aura::client::DragDropClientObserver* observer) override;
   void RemoveObserver(aura::client::DragDropClientObserver* observer) override;
 
-  // Overridden from void ui::WmDropHandler:
+  // ui::WmDropHandler
   void OnDragEnter(const gfx::PointF& point,
                    std::unique_ptr<ui::OSExchangeData> data,
                    int operation) override;
@@ -59,36 +64,36 @@
   void OnDragDrop(std::unique_ptr<ui::OSExchangeData> data) override;
   void OnDragLeave() override;
 
-  void OnDragSessionClosed(int operation);
+  // aura::WindowObserver
+  void OnWindowDestroyed(aura::Window* window) override;
 
- private:
-  void DragDropSessionCompleted();
+  void OnDragSessionClosed(int operation);
   void QuitRunLoop();
 
-  // Returns a DropTargetEvent to be passed to the DragDropDelegate, or null to
-  // abort the drag.
-  std::unique_ptr<ui::DropTargetEvent> CreateDropTargetEvent(
+  // Returns a DropTargetEvent to be passed to the DragDropDelegate.
+  // Updates the delegate if needed, which in its turn calls their
+  // OnDragExited/OnDragEntered, so after getting the event the delegate
+  // is ready to accept OnDragUpdated or OnPerformDrop.  Returns nullptr if
+  // drop is not possible.
+  std::unique_ptr<ui::DropTargetEvent> UpdateTargetAndCreateDropEvent(
       const gfx::PointF& point);
 
-  // Updates |drag_drop_delegate_| along with |window|.
-  void UpdateDragDropDelegate(aura::Window* window);
-
-  // Resets |drag_drop_delegate_|.
+  // Resets |drag_drop_delegate_|.  Calls OnDragExited() before resetting.
   void ResetDragDropTarget();
 
-  void PerformDrop();
-
   aura::Window* const root_window_;
 
   DesktopNativeCursorManager* cursor_manager_;
 
   ui::WmDragHandler* const drag_handler_;
 
+  // Last window under the mouse.
+  aura::Window* current_window_ = nullptr;
   // The delegate corresponding to the window located at the mouse position.
   aura::client::DragDropDelegate* drag_drop_delegate_ = nullptr;
 
   // The data to be delivered through the drag and drop.
-  std::unique_ptr<ui::OSExchangeData> os_exchange_data_ = nullptr;
+  std::unique_ptr<ui::OSExchangeData> data_to_drop_;
 
   // The most recent native coordinates of a drag.
   gfx::PointF last_drag_point_;
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc b/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc
index d159e51..04464c0 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc
@@ -288,10 +288,77 @@
   EXPECT_EQ(sample_data, string_data);
 
   EXPECT_EQ(1, dragdrop_delegate_->num_enters());
-  EXPECT_EQ(1, dragdrop_delegate_->num_enters());
   EXPECT_EQ(1, dragdrop_delegate_->num_updates());
   EXPECT_EQ(1, dragdrop_delegate_->num_drops());
   EXPECT_EQ(1, dragdrop_delegate_->num_exits());
 }
 
+TEST_F(DesktopDragDropClientOzoneTest, TargetDestroyedDuringDrag) {
+  const int suggested_operation =
+      ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE;
+
+  // Set the operation which the destination can accept.
+  dragdrop_delegate_->SetOperation(ui::DragDropTypes::DRAG_MOVE);
+
+  // Set the data which will be delivered.
+  const base::string16 sample_data = base::ASCIIToUTF16("ReceiveDrag");
+  std::unique_ptr<ui::OSExchangeData> data =
+      std::make_unique<ui::OSExchangeData>();
+  data->SetString(sample_data);
+
+  // Simulate that the drag enter/motion/leave events happen with the
+  // |suggested_operation| in the main window.
+  platform_window_->OnDragEnter(gfx::PointF(), std::move(data),
+                                suggested_operation);
+  platform_window_->OnDragMotion(gfx::PointF(), suggested_operation);
+  platform_window_->OnDragLeave();
+
+  // Create another window with its own DnD facility and simulate that the drag
+  // enters it and then the window is destroyed.
+  auto another_widget = std::make_unique<Widget>();
+  Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
+  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  params.bounds = gfx::Rect(100, 100);
+  another_widget->Init(std::move(params));
+  another_widget->Show();
+
+  aura::Window* another_window = another_widget->GetNativeWindow();
+  auto another_dragdrop_delegate = std::make_unique<FakeDragDropDelegate>();
+  aura::client::SetDragDropDelegate(another_window,
+                                    another_dragdrop_delegate.get());
+  another_dragdrop_delegate->SetOperation(ui::DragDropTypes::DRAG_COPY);
+
+  auto another_cursor_manager = std::make_unique<DesktopNativeCursorManager>();
+  auto another_platform_window = std::make_unique<FakePlatformWindow>();
+  ui::WmDragHandler* drag_handler =
+      ui::GetWmDragHandler(*(another_platform_window));
+  auto another_client = std::make_unique<DesktopDragDropClientOzone>(
+      another_window, another_cursor_manager.get(), drag_handler);
+  SetWmDropHandler(another_platform_window.get(), another_client.get());
+
+  std::unique_ptr<ui::OSExchangeData> another_data =
+      std::make_unique<ui::OSExchangeData>();
+  another_data->SetString(sample_data);
+  another_platform_window->OnDragEnter(gfx::PointF(), std::move(another_data),
+                                       suggested_operation);
+  another_platform_window->OnDragMotion(gfx::PointF(), suggested_operation);
+
+  another_widget->CloseWithReason(Widget::ClosedReason::kUnspecified);
+  another_widget.reset();
+
+  // The main window should have the typical record of a drag started and left.
+  EXPECT_EQ(1, dragdrop_delegate_->num_enters());
+  EXPECT_EQ(1, dragdrop_delegate_->num_updates());
+  EXPECT_EQ(0, dragdrop_delegate_->num_drops());
+  EXPECT_EQ(1, dragdrop_delegate_->num_exits());
+
+  // As the target window has closed and we have never provided another one,
+  // the number of exits should be zero despite that the platform window has
+  // notified the client about leaving the drag.
+  EXPECT_EQ(1, another_dragdrop_delegate->num_enters());
+  EXPECT_EQ(1, another_dragdrop_delegate->num_updates());
+  EXPECT_EQ(0, another_dragdrop_delegate->num_drops());
+  EXPECT_EQ(0, another_dragdrop_delegate->num_exits());
+}
+
 }  // namespace views
diff --git a/ui/views/window/dialog_delegate.h b/ui/views/window/dialog_delegate.h
index b6cd6fc..2b35fd9 100644
--- a/ui/views/window/dialog_delegate.h
+++ b/ui/views/window/dialog_delegate.h
@@ -197,11 +197,25 @@
   void SetButtons(int buttons);
   void SetButtonLabel(ui::DialogButton button, base::string16 label);
   void SetButtonEnabled(ui::DialogButton button, bool enabled);
-  void SetAcceptCallback(base::OnceClosure callback);
-  void SetCancelCallback(base::OnceClosure callback);
-  void SetCloseCallback(base::OnceClosure callback);
   void SetInitiallyFocusedView(View* view);
 
+  // Called when the user presses the dialog's "OK" button or presses the dialog
+  // accept accelerator, if there is one.
+  void SetAcceptCallback(base::OnceClosure callback);
+
+  // Called when the user presses the dialog's "Cancel" button or presses the
+  // dialog close accelerator (which is always VKEY_ESCAPE).
+  void SetCancelCallback(base::OnceClosure callback);
+
+  // Called when:
+  // * The user presses the dialog's close button, if it has one
+  // * The dialog's widget is closed via Widget::Close()
+  // NOT called when the dialog's widget is closed via Widget::CloseNow() - in
+  // that case, the normal widget close path is skipped, so no orderly teardown
+  // of the dialog's widget happens. The main way that can happen in production
+  // use is if the dialog's parent widget is closed.
+  void SetCloseCallback(base::OnceClosure callback);
+
   // Returns ownership of the extra view for this dialog, if one was provided
   // via SetExtraView(). This is only for use by DialogClientView; don't call
   // it.
diff --git a/ui/views/window/dialog_delegate_unittest.cc b/ui/views/window/dialog_delegate_unittest.cc
index 6096431..33e49328 100644
--- a/ui/views/window/dialog_delegate_unittest.cc
+++ b/ui/views/window/dialog_delegate_unittest.cc
@@ -515,4 +515,23 @@
   EXPECT_FALSE(cancelled);
 }
 
+TEST_F(DialogDelegateCloseTest, CloseParentWidgetDoesNotInvokeCloseCallback) {
+  auto* dialog = new DialogDelegateView();
+  std::unique_ptr<Widget> parent = CreateTestWidget();
+  Widget* widget = DialogDelegate::CreateDialogWidget(dialog, GetContext(),
+                                                      parent->GetNativeView());
+
+  bool closed = false;
+  dialog->SetCloseCallback(
+      base::BindLambdaForTesting([&closed]() { closed = true; }));
+
+  views::test::WidgetDestroyedWaiter parent_waiter(parent.get());
+  views::test::WidgetDestroyedWaiter dialog_waiter(widget);
+  parent->Close();
+  parent_waiter.Wait();
+  dialog_waiter.Wait();
+
+  EXPECT_FALSE(closed);
+}
+
 }  // namespace views
diff --git a/ui/webui/resources/cr_elements/cr_toast/BUILD.gn b/ui/webui/resources/cr_elements/cr_toast/BUILD.gn
index 8559f10a..a06ff0e 100644
--- a/ui/webui/resources/cr_elements/cr_toast/BUILD.gn
+++ b/ui/webui/resources/cr_elements/cr_toast/BUILD.gn
@@ -42,10 +42,7 @@
   html_file = "cr_toast_manager.html"
   html_type = "dom-module"
   auto_imports = [ "ui/webui/resources/html/assert.html|assert" ]
-  namespace_rewrites = [
-    "cr.toastManager.CrToastManagerElement|CrToastManagerElement",
-    "cr.toastManager.getToastManager|getToastManager",
-  ]
+  namespace_rewrites = [ "cr.toastManager.getToastManager|getToastManager" ]
 }
 
 js_type_check("closure_compile_module") {
diff --git a/ui/webui/resources/cr_elements/cr_toast/cr_toast_manager.js b/ui/webui/resources/cr_elements/cr_toast/cr_toast_manager.js
index 50fc1af7e..97995da 100644
--- a/ui/webui/resources/cr_elements/cr_toast/cr_toast_manager.js
+++ b/ui/webui/resources/cr_elements/cr_toast/cr_toast_manager.js
@@ -4,16 +4,16 @@
 
 cr.define('cr.toastManager', () => {
   /* eslint-disable */
-  /** @private {?cr.toastManager.CrToastManagerElement} */
+  /** @private {?CrToastManagerElement} */
   let toastManagerInstance = null;
   /* eslint-enable */
 
-  /** @return {!cr.toastManager.CrToastManagerElement} */
+  /** @return {!CrToastManagerElement} */
   /* #export */ function getToastManager() {
     return assert(toastManagerInstance);
   }
 
-  /** @param {?cr.toastManager.CrToastManagerElement} instance */
+  /** @param {?CrToastManagerElement} instance */
   function setInstance(instance) {
     assert(!instance || !toastManagerInstance);
     toastManagerInstance = instance;
@@ -23,7 +23,7 @@
    * @fileoverview Element which shows toasts with optional undo button.
    */
   // eslint-disable-next-line
-  /* #export */ let CrToastManagerElement = Polymer({
+  Polymer({
     is: 'cr-toast-manager',
 
     properties: {
@@ -94,7 +94,6 @@
 
   // #cr_define_end
   return {
-    CrToastManagerElement: CrToastManagerElement,
     getToastManager: getToastManager,
   };
 });
diff --git a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html
index 59ad0fb..efa9fba3 100644
--- a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html
+++ b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html
@@ -178,6 +178,7 @@
       <label id="prompt" for="searchInput" aria-hidden="true">[[label]]</label>
       <input id="searchInput"
           aria-labelledby="prompt"
+          autocomplete="off"
           type="search"
           on-input="onSearchTermInput"
           on-search="onSearchTermSearch"
diff --git a/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js b/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js
index d2e6c025..d3d9db47b 100644
--- a/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js
+++ b/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js
@@ -22,7 +22,7 @@
     indicatorType: {
       type: String,
       value: CrPolicyIndicatorType.NONE,
-      computed: 'getIndicatorTypeForPref_(pref.controlledBy, pref.enforcement)',
+      computed: 'getIndicatorTypeForPref_(pref.*, associatedValue)',
     },
 
     /** @private */
@@ -37,19 +37,40 @@
      * @type {!chrome.settingsPrivate.PrefObject|undefined}
      */
     pref: Object,
+
+    /**
+     * Optional value for the preference value this indicator is associated
+     * with. If this is set, no indicator will be shown if it is a member
+     * of |pref.userSelectableValues| and is not |pref.recommendedValue|.
+     * @type {*}
+     */
+    associatedValue: Object,
   },
 
   /**
-   * @param {!chrome.settingsPrivate.ControlledBy|undefined} controlledBy
-   * @param {!chrome.settingsPrivate.Enforcement|undefined} enforcement
-   * @return {CrPolicyIndicatorType} The indicator type based on |controlledBy|
-   *     and |enforcement|.
+   * @return {CrPolicyIndicatorType} The indicator type based on |pref| and
+   *    |associatedValue|.
    */
-  getIndicatorTypeForPref_(controlledBy, enforcement) {
+  getIndicatorTypeForPref_() {
+    const {enforcement, userSelectableValues, controlledBy, recommendedValue} =
+        this.pref;
     if (enforcement === chrome.settingsPrivate.Enforcement.RECOMMENDED) {
+      if (this.associatedValue !== undefined &&
+          this.associatedValue !== recommendedValue) {
+        return CrPolicyIndicatorType.NONE;
+      }
       return CrPolicyIndicatorType.RECOMMENDED;
     }
     if (enforcement === chrome.settingsPrivate.Enforcement.ENFORCED) {
+      // An enforced preference may also have some values still available for
+      // the user to select from.
+      if (userSelectableValues !== undefined) {
+        if (recommendedValue && this.associatedValue === recommendedValue) {
+          return CrPolicyIndicatorType.RECOMMENDED;
+        } else if (userSelectableValues.includes(this.associatedValue)) {
+          return CrPolicyIndicatorType.NONE;
+        }
+      }
       switch (controlledBy) {
         case chrome.settingsPrivate.ControlledBy.EXTENSION:
           return CrPolicyIndicatorType.EXTENSION;
@@ -74,18 +95,17 @@
   },
 
   /**
-   * @param {CrPolicyIndicatorType} indicatorType
    * @return {string} The tooltip text for |indicatorType|.
    * @private
    */
-  getIndicatorTooltipForPref_(indicatorType) {
+  getIndicatorTooltipForPref_() {
     if (!this.pref) {
       return '';
     }
 
     const matches = this.pref && this.pref.value === this.pref.recommendedValue;
     return this.getIndicatorTooltip(
-        indicatorType, this.pref.controlledByName || '', matches);
+        this.indicatorType, this.pref.controlledByName || '', matches);
   },
 
   /** @return {!Element} */
diff --git a/weblayer/BUILD.gn b/weblayer/BUILD.gn
index d92f4b7..0f05f81 100644
--- a/weblayer/BUILD.gn
+++ b/weblayer/BUILD.gn
@@ -439,6 +439,8 @@
       "browser/error_page_callback_proxy.h",
       "browser/fullscreen_callback_proxy.cc",
       "browser/fullscreen_callback_proxy.h",
+      "browser/infobar_service.cc",
+      "browser/infobar_service.h",
       "browser/new_tab_callback_proxy.cc",
       "browser/new_tab_callback_proxy.h",
       "browser/tab_callback_proxy.cc",
@@ -475,6 +477,7 @@
       "//components/embedder_support/android:web_contents_delegate",
       "//components/embedder_support/android/metrics",
       "//components/external_intents/android",
+      "//components/infobars/content",
       "//components/javascript_dialogs",
       "//components/location/android:settings",
       "//components/metrics",
diff --git a/weblayer/browser/DEPS b/weblayer/browser/DEPS
index a402f7e..2bfceca 100644
--- a/weblayer/browser/DEPS
+++ b/weblayer/browser/DEPS
@@ -18,6 +18,7 @@
   "+components/download/public/common",
   "+components/embedder_support",
   "+components/find_in_page",
+  "+components/infobars/content",
   "+components/infobars/core",
   "+components/javascript_dialogs",
   "+components/keyed_service/content",
diff --git a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java
index 9c49d2a..9edc74d 100644
--- a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java
+++ b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java
@@ -111,6 +111,19 @@
             }
         }
 
+        public static class UriCallbackHelper extends CallbackHelper {
+            private Uri mUri;
+
+            public void notifyCalled(Uri uri) {
+                mUri = uri;
+                notifyCalled();
+            }
+
+            public Uri getUri() {
+                return mUri;
+            }
+        }
+
         public static class NavigationCallbackValueRecorder {
             private List<String> mObservedValues =
                     Collections.synchronizedList(new ArrayList<String>());
@@ -139,6 +152,7 @@
         public NavigationCallbackValueRecorder loadProgressChangedCallback =
                 new NavigationCallbackValueRecorder();
         public CallbackHelper onFirstContentfulPaintCallback = new CallbackHelper();
+        public UriCallbackHelper onOldPageNoLongerRenderedCallback = new UriCallbackHelper();
 
         @Override
         public void onNavigationStarted(Navigation navigation) {
@@ -171,6 +185,11 @@
         }
 
         @Override
+        public void onOldPageNoLongerRendered(Uri newNavigationUri) {
+            onOldPageNoLongerRenderedCallback.notifyCalled(newNavigationUri);
+        }
+
+        @Override
         public void onLoadStateChanged(boolean isLoading, boolean toDifferentDocument) {
             loadStateChangedCallback.recordValue(
                     Boolean.toString(isLoading) + " " + Boolean.toString(toDifferentDocument));
@@ -206,6 +225,19 @@
         assertEquals(mCallback.onCompletedCallback.getHttpStatusCode(), 200);
     }
 
+    @MinWebLayerVersion(85)
+    @Test
+    @SmallTest
+    public void testOldPageNoLongerRendered() throws Exception {
+        InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl(URL1);
+        setNavigationCallback(activity);
+
+        int renderedCount = mCallback.onOldPageNoLongerRenderedCallback.getCallCount();
+        mActivityTestRule.navigateAndWait(URL2);
+        mCallback.onOldPageNoLongerRenderedCallback.waitForCallback(renderedCount);
+        assertEquals(Uri.parse(URL2), mCallback.onOldPageNoLongerRenderedCallback.getUri());
+    }
+
     @Test
     @SmallTest
     public void testLoadStateUpdates() throws Exception {
diff --git a/weblayer/browser/http_auth_handler_impl.cc b/weblayer/browser/http_auth_handler_impl.cc
index 5d9d6e2..bb9823e 100644
--- a/weblayer/browser/http_auth_handler_impl.cc
+++ b/weblayer/browser/http_auth_handler_impl.cc
@@ -28,7 +28,8 @@
 HttpAuthHandlerImpl::~HttpAuthHandlerImpl() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   auto* tab = TabImpl::FromWebContents(web_contents());
-  tab->CloseHttpAuthPrompt();
+  if (tab)
+    tab->CloseHttpAuthPrompt();
 }
 
 void HttpAuthHandlerImpl::Proceed(const base::string16& user,
diff --git a/weblayer/browser/infobar_service.cc b/weblayer/browser/infobar_service.cc
new file mode 100644
index 0000000..37af3091
--- /dev/null
+++ b/weblayer/browser/infobar_service.cc
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "weblayer/browser/infobar_service.h"
+
+namespace weblayer {
+
+InfoBarService::InfoBarService(content::WebContents* web_contents)
+    : infobars::ContentInfoBarManager(web_contents) {}
+
+InfoBarService::~InfoBarService() {}
+
+void InfoBarService::WebContentsDestroyed() {
+  // The WebContents is going away; be aggressively paranoid and delete
+  // ourselves lest other parts of the system attempt to add infobars or use
+  // us otherwise during the destruction.
+  web_contents()->RemoveUserData(UserDataKey());
+  // That was the equivalent of "delete this". This object is now destroyed;
+  // returning from this function is the only safe thing to do.
+}
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(InfoBarService)
+
+}  // namespace weblayer
diff --git a/weblayer/browser/infobar_service.h b/weblayer/browser/infobar_service.h
new file mode 100644
index 0000000..34c4025
--- /dev/null
+++ b/weblayer/browser/infobar_service.h
@@ -0,0 +1,46 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBLAYER_BROWSER_INFOBAR_SERVICE_H_
+#define WEBLAYER_BROWSER_INFOBAR_SERVICE_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "components/infobars/content/content_infobar_manager.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace weblayer {
+
+// WebLayer's specialization of ContentInfoBarManager, which ties the lifetime
+// of ContentInfoBarManager instances to that of the WebContents with which they
+// are associated.
+class InfoBarService : public infobars::ContentInfoBarManager,
+                       public content::WebContentsUserData<InfoBarService> {
+ public:
+  ~InfoBarService() override;
+  InfoBarService(const InfoBarService&) = delete;
+  InfoBarService& operator=(const InfoBarService&) = delete;
+
+ protected:
+  explicit InfoBarService(content::WebContents* web_contents);
+
+ private:
+  friend class content::WebContentsUserData<InfoBarService>;
+
+  // infobars::ContentInfoBarManager:
+  void WebContentsDestroyed() override;
+
+  WEB_CONTENTS_USER_DATA_KEY_DECL();
+};
+
+}  // namespace weblayer
+
+#endif  // WEBLAYER_BROWSER_INFOBAR_SERVICE_H_
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java
index d9434916..3957ed4 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java
@@ -166,6 +166,12 @@
         mNavigationControllerClient.onFirstContentfulPaint();
     }
 
+    @CalledByNative
+    private void onOldPageNoLongerRendered(String uri) throws RemoteException {
+        if (WebLayerFactoryImpl.getClientMajorVersion() < 85) return;
+        mNavigationControllerClient.onOldPageNoLongerRendered(uri);
+    }
+
     @NativeMethods
     interface Natives {
         void setNavigationControllerImpl(
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/WebLayerSiteSettingsClient.java b/weblayer/browser/java/org/chromium/weblayer_private/WebLayerSiteSettingsClient.java
index d047261..c3ecf8c 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/WebLayerSiteSettingsClient.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/WebLayerSiteSettingsClient.java
@@ -75,8 +75,8 @@
     public boolean isCategoryVisible(@Type int type) {
         return type == Type.ALL_SITES || type == Type.AUTOMATIC_DOWNLOADS || type == Type.CAMERA
                 || type == Type.COOKIES || type == Type.DEVICE_LOCATION || type == Type.JAVASCRIPT
-                || type == Type.MICROPHONE || type == Type.PROTECTED_MEDIA || type == Type.SOUND
-                || type == Type.USE_STORAGE;
+                || type == Type.MICROPHONE || type == Type.POPUPS || type == Type.PROTECTED_MEDIA
+                || type == Type.SOUND || type == Type.USE_STORAGE;
     }
 
     @Override
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigationControllerClient.aidl b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigationControllerClient.aidl
index 60132f87..73432f8b 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigationControllerClient.aidl
+++ b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigationControllerClient.aidl
@@ -6,6 +6,7 @@
 
 import org.chromium.weblayer_private.interfaces.IClientNavigation;
 import org.chromium.weblayer_private.interfaces.INavigation;
+import org.chromium.weblayer_private.interfaces.IObjectWrapper;
 
 /**
  * Interface used by NavigationController to inform the client of changes. This largely duplicates
@@ -29,4 +30,7 @@
   void loadProgressChanged(double progress) = 7;
 
   void onFirstContentfulPaint() = 8;
+
+  // Added in M85.
+  void onOldPageNoLongerRendered(in String uri) = 9;
 }
diff --git a/weblayer/browser/navigation_controller_impl.cc b/weblayer/browser/navigation_controller_impl.cc
index 3491e00..cabbd2c 100644
--- a/weblayer/browser/navigation_controller_impl.cc
+++ b/weblayer/browser/navigation_controller_impl.cc
@@ -4,6 +4,8 @@
 
 #include "weblayer/browser/navigation_controller_impl.h"
 
+#include <utility>
+
 #include "base/auto_reset.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -362,6 +364,14 @@
       observer.NavigationFailed(navigation);
   }
 
+  // Note InsertVisualStateCallback currently does not take into account
+  // any delays from surface sync, ie a frame submitted by renderer may not
+  // be displayed immediately. Such situations should be rare however, so
+  // this should be good enough for the purposes needed.
+  web_contents()->GetMainFrame()->InsertVisualStateCallback(base::BindOnce(
+      &NavigationControllerImpl::OldPageNoLongerRendered,
+      weak_ptr_factory_.GetWeakPtr(), navigation_handle->GetURL()));
+
   navigation_map_.erase(navigation_map_.find(navigation_handle));
 }
 
@@ -398,6 +408,20 @@
     observer.OnFirstContentfulPaint();
 }
 
+void NavigationControllerImpl::OldPageNoLongerRendered(const GURL& url,
+                                                       bool success) {
+#if defined(OS_ANDROID)
+  TRACE_EVENT0("weblayer",
+               "Java_NavigationControllerImpl_onOldPageNoLongerRendered");
+  JNIEnv* env = AttachCurrentThread();
+  Java_NavigationControllerImpl_onOldPageNoLongerRendered(
+      env, java_controller_,
+      base::android::ConvertUTF8ToJavaString(env, url.spec()));
+#endif
+  for (auto& observer : observers_)
+    observer.OnOldPageNoLongerRendered(url);
+}
+
 void NavigationControllerImpl::NotifyLoadStateChanged() {
 #if defined(OS_ANDROID)
   if (java_controller_) {
diff --git a/weblayer/browser/navigation_controller_impl.h b/weblayer/browser/navigation_controller_impl.h
index ede24464..ce96e14 100644
--- a/weblayer/browser/navigation_controller_impl.h
+++ b/weblayer/browser/navigation_controller_impl.h
@@ -9,6 +9,7 @@
 
 #include <memory>
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "build/build_config.h"
 #include "content/public/browser/navigation_controller.h"
@@ -107,6 +108,7 @@
   void LoadProgressChanged(double progress) override;
   void DidFirstVisuallyNonEmptyPaint() override;
 
+  void OldPageNoLongerRendered(const GURL& url, bool success);
   void NotifyLoadStateChanged();
 
   void DoNavigate(
@@ -127,6 +129,8 @@
   base::android::ScopedJavaGlobalRef<jobject> java_controller_;
 #endif
 
+  base::WeakPtrFactory<NavigationControllerImpl> weak_ptr_factory_{this};
+
   DISALLOW_COPY_AND_ASSIGN(NavigationControllerImpl);
 };
 
diff --git a/weblayer/browser/tab_impl.cc b/weblayer/browser/tab_impl.cc
index 58fedbd0..20f0ad8 100644
--- a/weblayer/browser/tab_impl.cc
+++ b/weblayer/browser/tab_impl.cc
@@ -50,6 +50,7 @@
 #include "weblayer/browser/file_select_helper.h"
 #include "weblayer/browser/host_content_settings_map_factory.h"
 #include "weblayer/browser/i18n_util.h"
+#include "weblayer/browser/infobar_service.h"
 #include "weblayer/browser/navigation_controller_impl.h"
 #include "weblayer/browser/page_load_metrics_initialize.h"
 #include "weblayer/browser/permissions/permission_manager_factory.h"
@@ -307,6 +308,7 @@
   InitializePageLoadMetricsForWebContents(web_contents_.get());
 
 #if defined(OS_ANDROID)
+  InfoBarService::CreateForWebContents(web_contents_.get());
   javascript_dialogs::TabModalDialogManager::CreateForWebContents(
       web_contents_.get(),
       std::make_unique<JavaScriptTabModalDialogManagerDelegateAndroid>(
diff --git a/weblayer/public/java/org/chromium/weblayer/NavigationCallback.java b/weblayer/public/java/org/chromium/weblayer/NavigationCallback.java
index 6b64268..3b85def 100644
--- a/weblayer/public/java/org/chromium/weblayer/NavigationCallback.java
+++ b/weblayer/public/java/org/chromium/weblayer/NavigationCallback.java
@@ -4,6 +4,8 @@
 
 package org.chromium.weblayer;
 
+import android.net.Uri;
+
 import androidx.annotation.NonNull;
 
 /**
@@ -112,4 +114,12 @@
      * non-empty layout has finished. This is *not* called for same-document navigations.
      */
     public void onFirstContentfulPaint() {}
+
+    /**
+     * Called after each navigation to indicate that the old page is no longer
+     * being rendered. Note this is not ordered with respect to onFirstContentfulPaint.
+     * @param newNavigationUri Uri of the new navigation.
+     * @since 85
+     */
+    public void onOldPageNoLongerRendered(@NonNull Uri newNavigationUri) {}
 }
diff --git a/weblayer/public/java/org/chromium/weblayer/NavigationController.java b/weblayer/public/java/org/chromium/weblayer/NavigationController.java
index 7eec22b..d36650ff 100644
--- a/weblayer/public/java/org/chromium/weblayer/NavigationController.java
+++ b/weblayer/public/java/org/chromium/weblayer/NavigationController.java
@@ -355,5 +355,13 @@
                 callback.onFirstContentfulPaint();
             }
         }
+
+        @Override
+        public void onOldPageNoLongerRendered(String uri) {
+            StrictModeWorkaround.apply();
+            for (NavigationCallback callback : mCallbacks) {
+                callback.onOldPageNoLongerRendered(Uri.parse(uri));
+            }
+        }
     }
 }
diff --git a/weblayer/public/navigation_observer.h b/weblayer/public/navigation_observer.h
index 6b0d2dd..86567cb5 100644
--- a/weblayer/public/navigation_observer.h
+++ b/weblayer/public/navigation_observer.h
@@ -5,6 +5,8 @@
 #ifndef WEBLAYER_PUBLIC_NAVIGATION_OBSERVER_H_
 #define WEBLAYER_PUBLIC_NAVIGATION_OBSERVER_H_
 
+class GURL;
+
 namespace weblayer {
 class Navigation;
 
@@ -95,6 +97,11 @@
   // This is fired after each navigation has completed to indicate that the
   // first paint after a non-empty layout has finished.
   virtual void OnFirstContentfulPaint() {}
+
+  // Called after each navigation to indicate that the old page is no longer
+  // being rendered. Note this is not ordered with respect to
+  // OnFirstContentfulPaint.
+  virtual void OnOldPageNoLongerRendered(const GURL& url) {}
 };
 
 }  // namespace weblayer