diff --git a/DEPS b/DEPS
index d01928e6..5c79a201 100644
--- a/DEPS
+++ b/DEPS
@@ -181,11 +181,11 @@
   # 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': '403c807971892049532870707729f0bc3e79e93a',
+  'skia_revision': '4a6e84920793bd6f98c4a15f2eda90b7e4074a7b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '07c5cd8f1d0654eb3e87b48f3f241919ada0d7ca',
+  'v8_revision': '1f5e1e29dd98ab0f0ff1f64183ce5ace076aeb5f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -193,11 +193,11 @@
   # 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': 'b84cdffeec6cb4aac16120bbd83917b9cd7b4c89',
+  'angle_revision': '99c274baf503ac6d7ece36c848bfcc1f1488e3f5',
   # 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': '7d0ce41d01de6236e9d3336502bf2c4a45a2c542',
+  'swiftshader_revision': '8a7067d8817495fc0af2da6d71d94f16693b9f3e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -244,7 +244,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': '9506caf2ea1f11687121fab0d7ad8a6e2a8abc75',
+  'catapult_revision': 'a47e1e9794a79e808878498b1146dca30c4902ae',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -775,7 +775,7 @@
     Var('chromium_git') + '/angle/angle.git' + '@' +  Var('angle_revision'),
 
   'src/third_party/dav1d/libdav1d':
-    Var('chromium_git') + '/external/github.com/videolan/dav1d.git' + '@' + '115fe773fe0e266a0918fbb950e1acfa5ee2b0bd',
+    Var('chromium_git') + '/external/github.com/videolan/dav1d.git' + '@' + '940eee483a852ec54349ef36f19713bb2b895b57',
 
   'src/third_party/dawn':
     Var('dawn_git') + '/dawn.git' + '@' +  Var('dawn_revision'),
@@ -904,7 +904,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '3a797afd61ff49d783b9b319e6cdfb33d493e3f4',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '0d462e99bc1f4e053b682249d3b4e2e972d11c6f',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1297,7 +1297,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'cce82035ba5bf724db4a143b6a46624239a66ff5',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '7f86589d1522ce8bfc59f6b569ca52496a53eb79',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1498,7 +1498,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '88d715c9115a5ce65c0bf660209dfeee9131ccd0',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'bd5874accf0faef28439ad32c1414bda8c9c25dc',
+    Var('webrtc_git') + '/src.git' + '@' + '340a62eb5a43fa476e1e7f1d76a49eb8f4e19fd5',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1568,7 +1568,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@3624da9ce38bf1716d3a7e89087bda9d1c82f498',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@fbc5981eaf58fdf3d305f316542ae956dc33a2f4',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 06f3b94..f807e32 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -866,6 +866,7 @@
 }
 
 grit("generate_components_resources") {
+  # Note that dev_ui_components_resources.grd is Chrome-only, so excluded.
   source = "../components/resources/components_resources.grd"
 
   # The .grd contains references to generated files.
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index cac7a1b..e60c28f 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -970,6 +970,7 @@
     mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
         header_client,
     bool* bypass_redirect_checks,
+    bool* disable_secure_dns,
     network::mojom::URLLoaderFactoryOverridePtr* factory_override) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index 4adac08..ce39cd7 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -207,6 +207,7 @@
       mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
           header_client,
       bool* bypass_redirect_checks,
+      bool* disable_secure_dns,
       network::mojom::URLLoaderFactoryOverridePtr* factory_override) override;
   uint32_t GetWebSocketOptions(content::RenderFrameHost* frame) override;
   bool WillCreateRestrictedCookieManager(
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc
index f3b2301e..fa955cc 100644
--- a/android_webview/lib/aw_main_delegate.cc
+++ b/android_webview/lib/aw_main_delegate.cc
@@ -186,9 +186,6 @@
       cl->AppendSwitch(switches::kWebViewEnableSharedImage);
       features.EnableIfNotSet(::features::kUseSkiaRenderer);
     } else {
-      // Disable OOP-D if viz for WebView not enabled.
-      features.DisableIfNotSet(::features::kVizDisplayCompositor);
-
       // Viz for WebView is required to support embedding CompositorFrameSinks
       // which is needed for UseSurfaceLayerForVideo feature.
       // https://crbug.com/853832
diff --git a/android_webview/tools/PRESUBMIT.py b/android_webview/tools/PRESUBMIT.py
index 6a31f718..2e523c31 100644
--- a/android_webview/tools/PRESUBMIT.py
+++ b/android_webview/tools/PRESUBMIT.py
@@ -19,14 +19,21 @@
   checks = []
 
   src_root = input_api.os_path.join(input_api.PresubmitLocalPath(), '..', '..')
-  checks.extend(input_api.canned_checks.GetPylint(
-      input_api, output_api, pylintrc='pylintrc',
-      # Allows pylint to find //build/android and //third_party/catapult/devil,
-      # which some of the scripts in this directory import.
-      extra_paths_list=[
-          input_api.os_path.join(src_root, 'build', 'android'),
-          input_api.os_path.join(src_root, 'third_party', 'catapult', 'devil'),
-      ]))
+  checks.extend(
+      input_api.canned_checks.GetPylint(
+          input_api,
+          output_api,
+          pylintrc='pylintrc',
+          # Allows pylint to find dependencies imported by scripts in this
+          # directory.
+          extra_paths_list=[
+              input_api.os_path.join(src_root, 'build', 'android'),
+              input_api.os_path.join(src_root, 'build', 'android', 'gyp'),
+              input_api.os_path.join(src_root, 'third_party', 'catapult',
+                                     'common', 'py_utils'),
+              input_api.os_path.join(src_root, 'third_party', 'catapult',
+                                     'devil'),
+          ]))
   checks.extend(_GetPythonUnitTests(input_api, output_api))
   return input_api.RunTests(checks, False)
 
diff --git a/android_webview/tools/apk_merger.py b/android_webview/tools/apk_merger.py
index 5acfc8a..84ab90e0 100755
--- a/android_webview/tools/apk_merger.py
+++ b/android_webview/tools/apk_merger.py
@@ -48,12 +48,12 @@
 BUILD_ANDROID_GYP_DIR = os.path.join(BUILD_ANDROID_DIR, 'gyp')
 sys.path.append(BUILD_ANDROID_GYP_DIR)
 
-import finalize_apk # pylint: disable=import-error,wrong-import-position
-from util import build_utils # pylint: disable=import-error,wrong-import-position
+import finalize_apk  # pylint: disable=wrong-import-position
+from util import build_utils  # pylint: disable=wrong-import-position
 
 sys.path.append(BUILD_ANDROID_DIR)
 
-from pylib import constants  # pylint: disable=import-error,wrong-import-position
+from pylib import constants  # pylint: disable=wrong-import-position
 
 DEFAULT_ZIPALIGN_PATH = os.path.join(
     SRC_DIR, 'third_party', 'android_sdk', 'public', 'build-tools',
@@ -254,9 +254,11 @@
 
     apksigner_jar = os.path.join(
         os.path.dirname(args.zipalign_path), 'lib', 'apksigner.jar')
-    finalize_apk.FinalizeApk(apksigner_jar, args.zipalign_path,
-                             tmp_apk, new_apk, args.keystore_path,
-                             args.key_password, args.key_name)
+    # TODO(https://crbug.com/1040240): remove the pylint suppression and pass
+    # the right value
+    finalize_apk.FinalizeApk(  # pylint: disable=no-value-for-parameter
+        apksigner_jar, args.zipalign_path, tmp_apk, new_apk, args.keystore_path,
+        args.key_password, args.key_name)
   finally:
     shutil.rmtree(tmp_dir)
   return 0
diff --git a/android_webview/tools/record_netlog.py b/android_webview/tools/record_netlog.py
index 17e4d21..522b8544 100755
--- a/android_webview/tools/record_netlog.py
+++ b/android_webview/tools/record_netlog.py
@@ -21,12 +21,12 @@
 sys.path.append(
     os.path.join(
         os.path.dirname(__file__), os.pardir, os.pardir, 'build', 'android'))
-import devil_chromium  # pylint: disable=import-error
-from devil.android import device_errors  # pylint: disable=import-error
-from devil.android import flag_changer  # pylint: disable=import-error
-from devil.android import device_utils  # pylint: disable=import-error
-from devil.android.tools import script_common  # pylint: disable=import-error
-from devil.utils import logging_common  # pylint: disable=import-error
+import devil_chromium
+from devil.android import device_errors
+from devil.android import flag_changer
+from devil.android import device_utils
+from devil.android.tools import script_common
+from devil.utils import logging_common
 
 WEBVIEW_COMMAND_LINE = 'webview-command-line'
 
diff --git a/android_webview/tools/remove_preinstalled_webview.py b/android_webview/tools/remove_preinstalled_webview.py
index 78c0e90..e46b3a8 100755
--- a/android_webview/tools/remove_preinstalled_webview.py
+++ b/android_webview/tools/remove_preinstalled_webview.py
@@ -36,13 +36,13 @@
 
 sys.path.append(os.path.join(
     os.path.dirname(__file__), os.pardir, os.pardir, 'build', 'android'))
-import devil_chromium  # pylint: disable=import-error
-from devil.android import device_errors  # pylint: disable=import-error
-from devil.android import device_utils  # pylint: disable=import-error
-from devil.android.sdk import keyevent  # pylint: disable=import-error
-from devil.android.tools import script_common  # pylint: disable=import-error
-from devil.android.tools import system_app  # pylint: disable=import-error
-from devil.utils import logging_common  # pylint: disable=import-error
+import devil_chromium
+from devil.android import device_errors
+from devil.android import device_utils
+from devil.android.sdk import keyevent
+from devil.android.tools import script_common
+from devil.android.tools import system_app
+from devil.utils import logging_common
 
 WEBVIEW_PACKAGES = ['com.android.webview', 'com.google.android.webview']
 
diff --git a/android_webview/tools/run_cts_test.py b/android_webview/tools/run_cts_test.py
index a14f2d1e..04b2b04 100644
--- a/android_webview/tools/run_cts_test.py
+++ b/android_webview/tools/run_cts_test.py
@@ -13,9 +13,10 @@
 
 sys.path.append(os.path.join(
     os.path.dirname(__file__), os.pardir, os.pardir, 'build', 'android'))
-import devil_chromium  # pylint: disable=import-error, unused-import
-from devil.android.ndk import abis  # pylint: disable=import-error
-from devil.android.sdk import version_codes  # pylint: disable=import-error
+import devil_chromium  # pylint: disable=unused-import
+from devil.android.ndk import abis
+from devil.android.sdk import version_codes
+
 
 class _RunCtsTest(unittest.TestCase):
   """Unittests for the run_cts module.
diff --git a/android_webview/tools/run_simpleperf.py b/android_webview/tools/run_simpleperf.py
index 7b8c869f8..9e73842 100755
--- a/android_webview/tools/run_simpleperf.py
+++ b/android_webview/tools/run_simpleperf.py
@@ -22,13 +22,13 @@
 
 sys.path.append(os.path.join(
     os.path.dirname(__file__), os.pardir, os.pardir, 'build', 'android'))
-import devil_chromium  # pylint: disable=import-error
-from devil.android import apk_helper # pylint: disable=import-error
-from devil.android import device_errors # pylint: disable=import-error
-from devil.android.ndk import abis  # pylint: disable=import-error
-from devil.android.tools import script_common  # pylint: disable=import-error
-from devil.utils import logging_common  # pylint: disable=import-error
-from py_utils import tempfile_ext  # pylint: disable=import-error
+import devil_chromium
+from devil.android import apk_helper
+from devil.android import device_errors
+from devil.android.ndk import abis
+from devil.android.tools import script_common
+from devil.utils import logging_common
+from py_utils import tempfile_ext
 
 _SUPPORTED_ARCH_DICT = {
     abis.ARM: 'arm',
diff --git a/ash/app_list/views/search_box_view.cc b/ash/app_list/views/search_box_view.cc
index 0882e6d..ba9d567 100644
--- a/ash/app_list/views/search_box_view.cc
+++ b/ash/app_list/views/search_box_view.cc
@@ -80,6 +80,12 @@
   return 1.f;
 }
 
+bool IsTrimmedQueryEmpty(const base::string16& query) {
+  base::string16 trimmed_query;
+  base::TrimWhitespace(query, base::TrimPositions::TRIM_ALL, &trimmed_query);
+  return trimmed_query.empty();
+}
+
 }  // namespace
 
 SearchBoxView::SearchBoxView(search_box::SearchBoxViewDelegate* delegate,
@@ -100,6 +106,7 @@
   if (app_list_features::IsZeroStateSuggestionsEnabled())
     set_show_close_button_when_active(true);
   SearchBoxViewBase::Init();
+  current_query_ = search_box()->GetText();
 }
 
 void SearchBoxView::ResetForShow() {
@@ -115,6 +122,7 @@
 
 void SearchBoxView::ClearSearch() {
   search_box::SearchBoxViewBase::ClearSearch();
+  current_query_.clear();
   app_list_view_->SetStateFromSearchBoxView(
       true, false /*triggered_by_contents_change*/);
 }
@@ -494,6 +502,12 @@
 
 void SearchBoxView::ContentsChanged(views::Textfield* sender,
                                     const base::string16& new_contents) {
+  if (IsTrimmedQueryEmpty(current_query_) && !IsSearchBoxTrimmedQueryEmpty()) {
+    // User enters a new search query. Record the action.
+    base::RecordAction(base::UserMetricsAction("AppList_SearchQueryStarted"));
+  }
+  current_query_ = new_contents;
+
   // Update autocomplete text highlight range to track user typed text.
   if (ShouldProcessAutocomplete())
     ResetHighlightRange();
diff --git a/ash/app_list/views/search_box_view.h b/ash/app_list/views/search_box_view.h
index a69a6b3..571fa846b 100644
--- a/ash/app_list/views/search_box_view.h
+++ b/ash/app_list/views/search_box_view.h
@@ -162,6 +162,8 @@
   bool HandleKeyEventForDisabledSearchBoxSelection(
       const ui::KeyEvent& key_event);
 
+  base::string16 current_query_;
+
   // The range of highlighted text for autocomplete.
   gfx::Range highlight_range_;
 
diff --git a/ash/app_list/views/search_box_view_unittest.cc b/ash/app_list/views/search_box_view_unittest.cc
index 99c90629..5955d66 100644
--- a/ash/app_list/views/search_box_view_unittest.cc
+++ b/ash/app_list/views/search_box_view_unittest.cc
@@ -20,6 +20,7 @@
 #include "ash/public/cpp/app_list/vector_icons/vector_icons.h"
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/metrics/user_action_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "ui/base/ime/composition_text.h"
 #include "ui/chromeos/search_box/search_box_constants.h"
@@ -417,6 +418,23 @@
       result_page_view->result_selection_controller()->selected_result());
 }
 
+TEST_F(SearchBoxViewTest, NewSearchQueryActionRecordedWhenUserType) {
+  base::UserActionTester user_action_tester;
+  // User starts to type a character in search box.
+  KeyPress(ui::VKEY_A);
+  EXPECT_EQ(1, user_action_tester.GetActionCount("AppList_SearchQueryStarted"));
+
+  // User continues to type another character.
+  KeyPress(ui::VKEY_B);
+  EXPECT_EQ(1, user_action_tester.GetActionCount("AppList_SearchQueryStarted"));
+
+  // User erases the query in the search box and types a new one.
+  KeyPress(ui::VKEY_BACK);
+  KeyPress(ui::VKEY_BACK);
+  KeyPress(ui::VKEY_C);
+  EXPECT_EQ(2, user_action_tester.GetActionCount("AppList_SearchQueryStarted"));
+}
+
 class SearchBoxViewAssistantButtonTest : public SearchBoxViewTest {
  public:
   SearchBoxViewAssistantButtonTest() = default;
diff --git a/ash/assistant/assistant_controller.h b/ash/assistant/assistant_controller.h
index 84d4990..d6f3594 100644
--- a/ash/assistant/assistant_controller.h
+++ b/ash/assistant/assistant_controller.h
@@ -142,6 +142,10 @@
     return &assistant_setup_controller_;
   }
 
+  AssistantStateController* state_controller() {
+    return &assistant_state_controller_;
+  }
+
   AssistantSuggestionsController* suggestions_controller() {
     return &assistant_suggestions_controller_;
   }
diff --git a/ash/assistant/assistant_web_ui_controller.cc b/ash/assistant/assistant_web_ui_controller.cc
index fe62790..148a42a 100644
--- a/ash/assistant/assistant_web_ui_controller.cc
+++ b/ash/assistant/assistant_web_ui_controller.cc
@@ -76,39 +76,47 @@
 
 AssistantWebUiController::~AssistantWebUiController() {
   assistant_controller_->RemoveObserver(this);
+  CloseUi();
 }
 
 void AssistantWebUiController::OnWidgetDestroying(views::Widget* widget) {
   ResetWebContainerView();
 }
 
-void AssistantWebUiController::OnAssistantControllerDestroying() {
-  if (!web_container_view_)
-    return;
+void AssistantWebUiController::OnAssistantControllerConstructed() {
+  assistant_controller_->state_controller()->AddObserver(this);
+}
 
-  // The view should not outlive the controller.
-  web_container_view_->GetWidget()->CloseNow();
-  DCHECK_EQ(nullptr, web_container_view_);
+void AssistantWebUiController::OnAssistantControllerDestroying() {
+  assistant_controller_->state_controller()->RemoveObserver(this);
 }
 
 void AssistantWebUiController::OnDeepLinkReceived(
     assistant::util::DeepLinkType type,
     const std::map<std::string, std::string>& params) {
-  if (!assistant::util::IsWebDeepLinkType(type, params))
-    return;
-
-  ShowUi();
-
-  // Open the url associated w/ the deep link.
-  web_container_view_->OpenUrl(
-      assistant::util::GetWebUrl(type, params).value());
+  if (assistant::util::IsWebDeepLinkType(type, params))
+    ShowUi(assistant::util::GetWebUrl(type, params).value());
 }
 
-void AssistantWebUiController::ShowUi() {
+void AssistantWebUiController::OnAssistantSettingsEnabled(bool enabled) {
+  if (!enabled)
+    CloseUi();
+}
+
+void AssistantWebUiController::ShowUi(const GURL& url) {
   if (!web_container_view_)
     CreateWebContainerView();
 
   web_container_view_->GetWidget()->Show();
+  web_container_view_->OpenUrl(url);
+}
+
+void AssistantWebUiController::CloseUi() {
+  if (!web_container_view_)
+    return;
+
+  web_container_view_->GetWidget()->CloseNow();
+  DCHECK_EQ(nullptr, web_container_view_);
 }
 
 void AssistantWebUiController::OnBackButtonPressed() {
diff --git a/ash/assistant/assistant_web_ui_controller.h b/ash/assistant/assistant_web_ui_controller.h
index d350122..28a78d37 100644
--- a/ash/assistant/assistant_web_ui_controller.h
+++ b/ash/assistant/assistant_web_ui_controller.h
@@ -10,6 +10,7 @@
 #include "ash/ash_export.h"
 #include "ash/assistant/assistant_controller_observer.h"
 #include "ash/assistant/assistant_web_view_delegate_impl.h"
+#include "ash/public/cpp/assistant/assistant_state.h"
 #include "base/macros.h"
 #include "ui/views/widget/widget_observer.h"
 
@@ -21,7 +22,8 @@
 
 // The class to manage Assistant web container view.
 class ASH_EXPORT AssistantWebUiController : public views::WidgetObserver,
-                                            public AssistantControllerObserver {
+                                            public AssistantControllerObserver,
+                                            public AssistantStateObserver {
  public:
   explicit AssistantWebUiController(AssistantController* assistant_controller);
   ~AssistantWebUiController() override;
@@ -30,17 +32,22 @@
   void OnWidgetDestroying(views::Widget* widget) override;
 
   // AssistantControllerObserver:
+  void OnAssistantControllerConstructed() override;
   void OnAssistantControllerDestroying() override;
   void OnDeepLinkReceived(
       assistant::util::DeepLinkType type,
       const std::map<std::string, std::string>& params) override;
 
+  // AssistantStateObserver:
+  void OnAssistantSettingsEnabled(bool enabled) override;
+
   void OnBackButtonPressed();
 
   AssistantWebContainerView* GetViewForTest();
 
  private:
-  void ShowUi();
+  void ShowUi(const GURL& url);
+  void CloseUi();
 
   // Constructs/resets |web_container_view_|.
   void CreateWebContainerView();
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 8b21931..e2130bf 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -1031,6 +1031,9 @@
 void ShelfLayoutManager::OnDisplayMetricsChanged(
     const display::Display& display,
     uint32_t changed_metrics) {
+  if (updating_bounds_)
+    return;
+
   // Update |user_work_area_bounds_| for the new display arrangement.
   CalculateTargetBoundsAndUpdateWorkArea(hotseat_state());
 }
@@ -2343,8 +2346,6 @@
     drag_amount_ = 0.f;
   }
 
-  MaybeStartDragWindowFromShelf(event_in_screen, /*scroll_y=*/base::nullopt);
-
   return true;
 }
 
@@ -2398,7 +2399,7 @@
           event_in_screen.AsGestureEvent()->details().velocity_y();
     }
     LayoutShelf();
-    MaybeUpdateWindowDrag(event_in_screen, scroll_x, scroll_y);
+    MaybeUpdateWindowDrag(event_in_screen, gfx::Vector2dF(scroll_x, scroll_y));
   }
 }
 
@@ -2628,7 +2629,7 @@
 
 bool ShelfLayoutManager::MaybeStartDragWindowFromShelf(
     const ui::LocatedEvent& event_in_screen,
-    base::Optional<float> scroll_y) {
+    const gfx::Vector2dF& scroll) {
   if (!features::IsDragFromShelfToHomeOrOverviewEnabled())
     return false;
   if (!IsTabletModeEnabled())
@@ -2647,6 +2648,8 @@
   if (hotseat_state() == HotseatState::kShown)
     return false;
 
+  gfx::PointF event_start_location = event_in_screen.location_f();
+
   // If hotseat is hidden when drag starts, do not start drag window if hotseat
   // hasn't been fully dragged up.
   if (hotseat_state() == HotseatState::kHidden) {
@@ -2657,13 +2660,18 @@
     if (drag_amount_ > full_drag_amount)
       return false;
   } else if (hotseat_state() == HotseatState::kExtended) {
+    // Window drag will not start until it's determined that the gesture is
+    // going up. The effective starting position will thus be the previous event
+    // location.
+    event_start_location -= scroll;
+
     // If the start location is above the shelf (e.g., on the extended hotseat),
     // do not allow the drag.
     const gfx::Rect shelf_bounds = GetVisibleShelfBounds();
-    if (event_in_screen.location().y() < shelf_bounds.y())
+    if (event_start_location.y() < shelf_bounds.y())
       return false;
     // Do not start drag if it's a downward update event.
-    if (scroll_y.has_value() && *scroll_y > 0)
+    if (scroll.y() >= 0)
       return false;
   }
 
@@ -2680,23 +2688,29 @@
     return false;
 
   window_drag_controller_ = std::make_unique<DragWindowFromShelfController>(
-      window, event_in_screen.location_f(), hotseat_state());
+      window, event_start_location, hotseat_state());
+
+  // In extended state, the effective start location is the previous event, so
+  // send additional drag event, so the controller doesn't skip the current
+  // drag location.
+  if (hotseat_state() == HotseatState::kExtended) {
+    window_drag_controller_->Drag(event_in_screen.location_f(), scroll.x(),
+                                  scroll.y());
+  }
   return true;
 }
 
 void ShelfLayoutManager::MaybeUpdateWindowDrag(
     const ui::LocatedEvent& event_in_screen,
-    float scroll_x,
-    float scroll_y) {
+    const gfx::Vector2dF& scroll) {
   if (!IsWindowDragInProgress() &&
-      !MaybeStartDragWindowFromShelf(event_in_screen,
-                                     base::make_optional(scroll_y))) {
+      !MaybeStartDragWindowFromShelf(event_in_screen, scroll)) {
     return;
   }
 
   DCHECK_EQ(drag_status_, kDragInProgress);
-  window_drag_controller_->Drag(event_in_screen.location_f(), scroll_x,
-                                scroll_y);
+  window_drag_controller_->Drag(event_in_screen.location_f(), scroll.x(),
+                                scroll.y());
 }
 
 base::Optional<ShelfWindowDragResult> ShelfLayoutManager::MaybeEndWindowDrag(
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index f415a8014..49b3e7f 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -535,10 +535,9 @@
 
   // Maybe start/update/end the window drag when swiping up from the shelf.
   bool MaybeStartDragWindowFromShelf(const ui::LocatedEvent& event_in_screen,
-                                     base::Optional<float> scroll_y);
+                                     const gfx::Vector2dF& scroll);
   void MaybeUpdateWindowDrag(const ui::LocatedEvent& event_in_screen,
-                             float scroll_x,
-                             float scroll_y);
+                             const gfx::Vector2dF& scroll);
   base::Optional<DragWindowFromShelfController::ShelfWindowDragResult>
   MaybeEndWindowDrag(const ui::LocatedEvent& event_in_screen);
   // If overview session is active, goes to home screen if the gesture should
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index a404a86..aed7e0ad 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -5108,6 +5108,57 @@
   }
 }
 
+// Tests that downward swipe on shelf does not start window drag.
+TEST_F(ShelfLayoutManagerWindowDraggingTest,
+       DownwardSwipeDoesnotStartWnidowDrag) {
+  // Starts the drag from the center of the shelf's bottom.
+  const gfx::Rect shelf_bounds = GetShelfWidget()->GetWindowBoundsInScreen();
+  gfx::Point start = shelf_bounds.top_center();
+  std::unique_ptr<aura::Window> window =
+      AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
+  wm::ActivateWindow(window.get());
+
+  // Tests that downward swipe on shelf does not start window drag, nor change
+  // the window transform when hotseat is hidden.
+  ASSERT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state());
+  StartScroll(start);
+  EXPECT_FALSE(IsWindowDragInProgress());
+  EXPECT_TRUE(window->transform().IsIdentity());
+
+  UpdateScroll(shelf_bounds.height() / 2);
+  EXPECT_FALSE(IsWindowDragInProgress());
+  EXPECT_TRUE(window->transform().IsIdentity());
+
+  UpdateScroll(shelf_bounds.height() / 2);
+  EXPECT_FALSE(IsWindowDragInProgress());
+  EXPECT_TRUE(window->transform().IsIdentity());
+
+  EndScroll(/*is_fling=*/false, 0.f);
+  EXPECT_FALSE(IsWindowDragInProgress());
+  EXPECT_TRUE(window->transform().IsIdentity());
+
+  // Tests that downward swipe on shelf does not start window drag, nor change
+  // the window transform when hotseat is extended.
+  SwipeUpOnShelf();
+  ASSERT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state());
+
+  StartScroll(start);
+  EXPECT_FALSE(IsWindowDragInProgress());
+  EXPECT_TRUE(window->transform().IsIdentity());
+
+  UpdateScroll(shelf_bounds.height() / 2);
+  EXPECT_FALSE(IsWindowDragInProgress());
+  EXPECT_TRUE(window->transform().IsIdentity());
+
+  UpdateScroll(shelf_bounds.height() / 2);
+  EXPECT_FALSE(IsWindowDragInProgress());
+  EXPECT_TRUE(window->transform().IsIdentity());
+
+  EndScroll(/*is_fling=*/false, 0.f);
+  EXPECT_FALSE(IsWindowDragInProgress());
+  EXPECT_TRUE(window->transform().IsIdentity());
+}
+
 // Test that drag from shelf when overview is active is a no-op.
 TEST_F(ShelfLayoutManagerWindowDraggingTest, NoOpInOverview) {
   const gfx::Rect shelf_widget_bounds =
diff --git a/ash/system/screen_security/screen_switch_check_controller.cc b/ash/system/screen_security/screen_switch_check_controller.cc
index a1fb2e2..1dfc70d 100644
--- a/ash/system/screen_security/screen_switch_check_controller.cc
+++ b/ash/system/screen_security/screen_switch_check_controller.cc
@@ -26,6 +26,9 @@
     AddChildView(new views::MessageBoxView(views::MessageBoxView::InitParams(
         l10n_util::GetStringUTF16(IDS_DESKTOP_CASTING_ACTIVE_MESSAGE))));
     SetLayoutManager(std::make_unique<views::FillLayout>());
+    DialogDelegate::set_button_label(
+        ui::DIALOG_BUTTON_OK,
+        l10n_util::GetStringUTF16(IDS_DESKTOP_CASTING_ACTIVE_CONTINUE));
   }
   ~CancelCastingDialog() override = default;
 
@@ -37,14 +40,6 @@
     return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
   }
 
-  base::string16 GetDialogButtonLabel(ui::DialogButton button) const override {
-    if (button == ui::DIALOG_BUTTON_OK)
-      return l10n_util::GetStringUTF16(IDS_DESKTOP_CASTING_ACTIVE_CONTINUE);
-    if (button == ui::DIALOG_BUTTON_CANCEL)
-      return l10n_util::GetStringUTF16(IDS_APP_CANCEL);
-    return base::string16();
-  }
-
   bool Cancel() override {
     std::move(callback_).Run(false);
     return true;
diff --git a/ash/system/unified/unified_slider_bubble_controller.cc b/ash/system/unified/unified_slider_bubble_controller.cc
index 47fe090a..963cafdc 100644
--- a/ash/system/unified/unified_slider_bubble_controller.cc
+++ b/ash/system/unified/unified_slider_bubble_controller.cc
@@ -15,6 +15,8 @@
 #include "ash/system/unified/unified_system_tray.h"
 #include "ash/system/unified/unified_system_tray_bubble.h"
 #include "ash/system/unified/unified_system_tray_view.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "chromeos/constants/chromeos_switches.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 
 using chromeos::CrasAudioHandler;
@@ -165,9 +167,7 @@
   init_params.anchor_rect = tray_->shelf()->GetSystemTrayAnchorRect();
   // Decrease bottom and right insets to compensate for the adjustment of
   // the respective edges in Shelf::GetSystemTrayAnchorRect().
-  init_params.insets = gfx::Insets(
-      kUnifiedMenuPadding, kUnifiedMenuPadding, kUnifiedMenuPadding - 1,
-      kUnifiedMenuPadding - (base::i18n::IsRTL() ? 0 : 1));
+  init_params.insets = GetInsets();
   init_params.corner_radius = kUnifiedTrayCornerRadius;
   init_params.has_shadow = false;
   init_params.translucent = true;
@@ -220,4 +220,27 @@
       &UnifiedSliderBubbleController::CloseBubble);
 }
 
+gfx::Insets UnifiedSliderBubbleController::GetInsets() {
+  // Decrease bottom and right insets to compensate for the adjustment of
+  // the respective edges in Shelf::GetSystemTrayAnchorRect().
+  gfx::Insets insets = gfx::Insets(
+      kUnifiedMenuPadding, kUnifiedMenuPadding, kUnifiedMenuPadding - 1,
+      kUnifiedMenuPadding - (base::i18n::IsRTL() ? 0 : 1));
+
+  // The work area in tablet mode always uses the in-app shelf height, which
+  // ignores the height of the hotseat. We need to add additional height to the
+  // baseline to compensate.
+  bool in_tablet_mode = Shell::Get()->tablet_mode_controller() &&
+                        Shell::Get()->tablet_mode_controller()->InTabletMode();
+  bool is_bottom_alignment =
+      tray_->shelf()->alignment() == ShelfAlignment::kBottom;
+  if (chromeos::switches::ShouldShowShelfHotseat() && in_tablet_mode &&
+      !ShelfConfig::Get()->is_in_app() && is_bottom_alignment) {
+    insets.set_bottom(insets.bottom() +
+                      kPopupCollectionHotseatHeightCompensation);
+  }
+
+  return insets;
+}
+
 }  // namespace ash
diff --git a/ash/system/unified/unified_slider_bubble_controller.h b/ash/system/unified/unified_slider_bubble_controller.h
index 834bce6..cd0105a 100644
--- a/ash/system/unified/unified_slider_bubble_controller.h
+++ b/ash/system/unified/unified_slider_bubble_controller.h
@@ -68,6 +68,9 @@
   // Start auto close timer.
   void StartAutoCloseTimer();
 
+  // Returns the insets for the bubble.
+  gfx::Insets GetInsets();
+
   // Unowned.
   UnifiedSystemTray* const tray_;
 
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc
index f754a05..bc6462c 100644
--- a/ash/wm/overview/overview_window_drag_controller.cc
+++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -558,10 +558,10 @@
       },
       overview_grid)};
 
-  // Attempt to move a window to a different desk.
   if (virtual_desks_bar_enabled_) {
     item_->SetOpacity(original_opacity_);
 
+    // Attempt to move a window to a different desk.
     if (overview_grid->MaybeDropItemOnDeskMiniView(rounded_screen_point,
                                                    item_)) {
       // Window was successfully moved to another desk, and |item_| was
diff --git a/base/BUILD.gn b/base/BUILD.gn
index ea4c4d7..e48850c 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -3224,9 +3224,13 @@
   java_library("jni_java") {
     supports_android = true
     sources = [
+      "android/java/src/org/chromium/base/JniException.java",
       "android/java/src/org/chromium/base/JniStaticTestMocker.java",
+      "android/java/src/org/chromium/base/NativeLibraryLoadedStatus.java",
       "android/java/src/org/chromium/base/annotations/NativeMethods.java",
     ]
+    srcjar_deps = [ ":base_build_config_gen" ]
+    jar_excluded_patterns = [ "*/BuildConfig.class" ]
   }
 
   android_library("base_java") {
@@ -3713,7 +3717,7 @@
     args = [
       "--encode=mach_fuzzer.MachMessage",
       "-I",
-      rebase_path("//testing/libfuzzer/fuzzers/mach"),
+      rebase_path("//"),
       rebase_path(inputs[0]),
     ]
   }
diff --git a/base/android/java/src/org/chromium/base/JniException.java b/base/android/java/src/org/chromium/base/JniException.java
new file mode 100644
index 0000000..97780b53
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/JniException.java
@@ -0,0 +1,14 @@
+// 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.
+
+package org.chromium.base;
+
+/**
+ *  Error when calling native methods.
+ */
+public class JniException extends RuntimeException {
+    public JniException(String msg) {
+        super(msg);
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/NativeLibraryLoadedStatus.java b/base/android/java/src/org/chromium/base/NativeLibraryLoadedStatus.java
new file mode 100644
index 0000000..660b7bc5
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/NativeLibraryLoadedStatus.java
@@ -0,0 +1,41 @@
+// 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.
+
+package org.chromium.base;
+
+/**
+ * Exposes native library loading status.
+ */
+public class NativeLibraryLoadedStatus {
+    /**
+     * Interface for querying native method availability.
+     */
+    public interface NativeLibraryLoadedStatusProvider {
+        boolean areMainDexNativeMethodsReady();
+        boolean areNativeMethodsReady();
+    }
+
+    private static NativeLibraryLoadedStatusProvider sProvider;
+
+    public static void checkLoaded(boolean isMainDex) {
+        // Necessary to make sure all of these calls are stripped in release builds.
+        if (!BuildConfig.DCHECK_IS_ON) return;
+
+        if (sProvider == null) return;
+
+        boolean nativeMethodsReady = isMainDex ? sProvider.areMainDexNativeMethodsReady()
+                                               : sProvider.areNativeMethodsReady();
+        if (!nativeMethodsReady) {
+            throw new JniException("Native method called before the native library was ready.");
+        }
+    }
+
+    public static void setProvider(NativeLibraryLoadedStatusProvider statusProvider) {
+        sProvider = statusProvider;
+    }
+
+    public static NativeLibraryLoadedStatusProvider getProviderForTesting() {
+        return sProvider;
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
index bb7b5a5d..19469e77 100644
--- a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
@@ -25,6 +25,8 @@
 import org.chromium.base.FileUtils;
 import org.chromium.base.JNIUtils;
 import org.chromium.base.Log;
+import org.chromium.base.NativeLibraryLoadedStatus;
+import org.chromium.base.NativeLibraryLoadedStatus.NativeLibraryLoadedStatusProvider;
 import org.chromium.base.StreamUtil;
 import org.chromium.base.StrictModeContext;
 import org.chromium.base.TraceEvent;
@@ -32,6 +34,7 @@
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.MainDex;
 import org.chromium.base.annotations.NativeMethods;
+import org.chromium.base.annotations.RemovableInRelease;
 import org.chromium.base.compat.ApiHelperForM;
 import org.chromium.base.metrics.CachedMetrics;
 import org.chromium.base.metrics.RecordHistogram;
@@ -242,6 +245,23 @@
         return NativeLibraries.sEnableLinkerTests;
     }
 
+    @RemovableInRelease
+    public void enableJniChecks() {
+        if (!BuildConfig.DCHECK_IS_ON) return;
+
+        NativeLibraryLoadedStatus.setProvider(new NativeLibraryLoadedStatusProvider() {
+            @Override
+            public boolean areMainDexNativeMethodsReady() {
+                return mLoadState >= LoadState.MAIN_DEX_LOADED;
+            }
+
+            @Override
+            public boolean areNativeMethodsReady() {
+                return isInitialized();
+            }
+        });
+    }
+
     /**
      * Return if library is already loaded successfully by the zygote.
      */
diff --git a/base/android/javatests/src/org/chromium/base/library_loader/EarlyNativeTest.java b/base/android/javatests/src/org/chromium/base/library_loader/EarlyNativeTest.java
index 920fb4f..371477ed 100644
--- a/base/android/javatests/src/org/chromium/base/library_loader/EarlyNativeTest.java
+++ b/base/android/javatests/src/org/chromium/base/library_loader/EarlyNativeTest.java
@@ -7,11 +7,15 @@
 import android.content.pm.ApplicationInfo;
 import android.support.test.filters.SmallTest;
 
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.BuildConfig;
+import org.chromium.base.JniException;
+import org.chromium.base.NativeLibraryLoadedStatus;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.MainDex;
 import org.chromium.base.annotations.NativeMethods;
@@ -21,7 +25,7 @@
 import java.util.concurrent.TimeoutException;
 
 /**
- * Tests for {@link LibraryLoader#ensureMainDexInitialized}.
+ * Tests for early JNI initialization.
  */
 @RunWith(BaseJUnit4ClassRunner.class)
 @JNINamespace("base")
@@ -36,6 +40,11 @@
         mEnsureMainDexInitializedFinished = new CallbackHelper();
     }
 
+    @After
+    public void tearDown() {
+        NativeLibraryLoadedStatus.setProvider(null);
+    }
+
     private class TestLibraryLoader extends LibraryLoader {
         @Override
         protected void loadMainDexAlreadyLocked(ApplicationInfo appInfo, boolean inZygote) {
@@ -78,6 +87,7 @@
     private void doTestFullInitializationDoesntBlockMainDexInitialization(final boolean initialize)
             throws Exception {
         final TestLibraryLoader loader = new TestLibraryLoader();
+        loader.enableJniChecks();
         loader.setLibraryProcessType(LibraryProcessType.PROCESS_BROWSER);
         final Thread t1 = new Thread(() -> {
             if (initialize) {
@@ -110,4 +120,42 @@
     public void testLoadDoesntBlockMainDexInitialization() throws Exception {
         doTestFullInitializationDoesntBlockMainDexInitialization(false);
     }
+
+    @Test
+    @SmallTest
+    public void testNativeMethodsReadyAfterLibraryInitialized() {
+        LibraryLoader.getInstance().enableJniChecks();
+
+        Assert.assertFalse(
+                NativeLibraryLoadedStatus.getProviderForTesting().areMainDexNativeMethodsReady());
+        Assert.assertFalse(
+                NativeLibraryLoadedStatus.getProviderForTesting().areNativeMethodsReady());
+
+        LibraryLoader.getInstance().ensureMainDexInitialized();
+        Assert.assertTrue(
+                NativeLibraryLoadedStatus.getProviderForTesting().areMainDexNativeMethodsReady());
+        Assert.assertFalse(
+                NativeLibraryLoadedStatus.getProviderForTesting().areNativeMethodsReady());
+
+        LibraryLoader.getInstance().ensureInitialized();
+        Assert.assertTrue(
+                NativeLibraryLoadedStatus.getProviderForTesting().areMainDexNativeMethodsReady());
+        Assert.assertTrue(
+                NativeLibraryLoadedStatus.getProviderForTesting().areNativeMethodsReady());
+    }
+
+    @Test
+    @SmallTest
+    public void testNativeMethodsNotReadyThrows() {
+        LibraryLoader.getInstance().enableJniChecks();
+
+        try {
+            // Test is a no-op if dcheck isn't on.
+            if (BuildConfig.DCHECK_IS_ON) {
+                EarlyNativeTestJni.get().isCommandLineInitialized();
+                Assert.fail("Using JNI before the library is loaded should throw an exception.");
+            }
+        } catch (JniException e) {
+        }
+    }
 }
diff --git a/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java b/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java
index 1268bcf..990b717 100644
--- a/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java
+++ b/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java
@@ -21,6 +21,7 @@
 import com.squareup.javapoet.TypeSpec;
 
 import org.chromium.base.JniStaticTestMocker;
+import org.chromium.base.NativeLibraryLoadedStatus;
 import org.chromium.base.annotations.CheckDiscard;
 import org.chromium.base.annotations.MainDex;
 import org.chromium.base.annotations.NativeMethods;
@@ -67,8 +68,10 @@
     private static final Class<NativeMethods> JNI_STATIC_NATIVES_CLASS = NativeMethods.class;
     private static final Class<MainDex> MAIN_DEX_CLASS = MainDex.class;
     private static final Class<CheckDiscard> CHECK_DISCARD_CLASS = CheckDiscard.class;
-    private static final String CHECK_DISCARD_CRBUG = "crbug.com/993421";
+    private static final Class<NativeLibraryLoadedStatus> JNI_STATUS_CLASS =
+            NativeLibraryLoadedStatus.class;
 
+    private static final String CHECK_DISCARD_CRBUG = "crbug.com/993421";
     private static final String NATIVE_WRAPPER_CLASS_POSTFIX = "Jni";
 
     // The native class name and package name used in debug.
@@ -394,6 +397,7 @@
                     throw new UnsupportedOperationException($noMockExceptionString);
                 }
             }
+            NativeLibraryLoadedStatus.checkLoaded($isMainDex)
             return new {classname}Jni();
         }
          */
@@ -402,6 +406,7 @@
                                 + "The current configuration requires all native "
                                 + "implementations to have a mock instance.",
                         nativeInterfaceType);
+
         MethodSpec instanceGetter =
                 MethodSpec.methodBuilder("get")
                         .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
@@ -416,6 +421,8 @@
                                 noMockExceptionString)
                         .endControlFlow()
                         .endControlFlow()
+                        .addStatement("$T.$N($L)", ClassName.get(JNI_STATUS_CLASS), "checkLoaded",
+                                isMainDex)
                         .addStatement("return new $N()", name)
                         .build();
 
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
index e824a84..494100f 100644
--- a/base/test/launcher/test_launcher.cc
+++ b/base/test/launcher/test_launcher.cc
@@ -15,7 +15,6 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/environment.h"
-#include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
@@ -466,47 +465,10 @@
   int exit_code;
 };
 
-// Returns true if child test processes should have dedicated temporary
-// directories.
-constexpr bool SupportsPerChildTempDirs() {
-#if defined(OS_WIN) || defined(OS_MACOSX)
-  return true;
-#else
-  // TODO(https://crbug.com/1038857): Enable for Linux and Fuchsia.
-  return false;
-#endif
-}
-
-// Returns the path to a temporary directory within |task_temp_dir| for the
-// child process of index |child_index|, or an empty FilePath if per-child temp
-// dirs are not supported.
-FilePath CreateChildTempDirIfSupported(const FilePath& task_temp_dir,
-                                       int child_index) {
-  if (!SupportsPerChildTempDirs())
-    return FilePath();
-  FilePath child_temp = task_temp_dir.AppendASCII(NumberToString(child_index));
-  CHECK(CreateDirectoryAndGetError(child_temp, nullptr));
-  return child_temp;
-}
-
-// Adds the platform-specific variable setting |temp_dir| as a process's
-// temporary directory to |environment|.
-void SetTemporaryDirectory(const FilePath& temp_dir,
-                           EnvironmentMap* environment) {
-#if defined(OS_WIN)
-  environment->emplace(L"TMP", temp_dir.value());
-#elif defined(OS_MACOSX)
-  environment->emplace("MAC_CHROMIUM_TMPDIR", temp_dir.value());
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
-  environment->emplace("TMPDIR", temp_dir.value());
-#endif
-}
-
 // This launches the child test process, waits for it to complete,
 // and returns child process results.
 ChildProcessResults DoLaunchChildTestProcess(
     const CommandLine& command_line,
-    const FilePath& process_temp_dir,
     TimeDelta timeout,
     const TestLauncher::LaunchOptions& test_launch_options,
     bool redirect_stdio,
@@ -524,10 +486,6 @@
   }
 
   LaunchOptions options;
-
-  // Tell the child process to use its designated temporary directory.
-  if (!process_temp_dir.empty())
-    SetTemporaryDirectory(process_temp_dir, &options.environment);
 #if defined(OS_WIN)
 
   options.inherit_mode = test_launch_options.inherit_mode;
@@ -623,26 +581,25 @@
  private:
   // Called to check if the next batch has to run on the same
   // sequence task runner and using the same temporary directory.
-  static bool ShouldReuseStateFromLastBatch(
+  bool ShouldReuseStateFromLastBatch(
       const std::vector<std::string>& test_names) {
     return test_names.size() == 1u &&
            test_names.front().find(kPreTestPrefix) != std::string::npos;
   }
 
-  // Launches the next child process on |task_runner| and clears
-  // |last_task_temp_dir| from the previous task.
-  void LaunchNextTask(scoped_refptr<TaskRunner> task_runner,
-                      const FilePath& last_task_temp_dir);
+  // Launch next child process on |task_runner|,
+  // and clear |temp_dir| from previous process.
+  void LaunchNextTask(scoped_refptr<TaskRunner> task_runner, FilePath temp_dir);
 
-  // Forwards |last_task_temp_dir| and launches the next task on main thread.
+  // Forward |temp_dir| and Launch next task on main thread.
   // The method is called on |task_runner|.
   void ClearAndLaunchNext(scoped_refptr<TaskRunner> main_thread_runner,
                           scoped_refptr<TaskRunner> task_runner,
-                          const FilePath& last_task_temp_dir) {
+                          const FilePath& temp_dir) {
     main_thread_runner->PostTask(
         FROM_HERE,
         BindOnce(&TestRunner::LaunchNextTask, weak_ptr_factory_.GetWeakPtr(),
-                 task_runner, last_task_temp_dir));
+                 task_runner, temp_dir));
   }
 
   ThreadChecker thread_checker_;
@@ -682,13 +639,12 @@
 }
 
 void TestRunner::LaunchNextTask(scoped_refptr<TaskRunner> task_runner,
-                                const FilePath& last_task_temp_dir) {
+                                FilePath temp_dir) {
   DCHECK(thread_checker_.CalledOnValidThread());
   // delete previous temporary directory
-  if (!last_task_temp_dir.empty() &&
-      !DeleteFileRecursively(last_task_temp_dir)) {
+  if (!temp_dir.empty() && !DeleteFileRecursively(temp_dir)) {
     // This needs to be non-fatal at least for Windows.
-    LOG(WARNING) << "Failed to delete " << last_task_temp_dir.AsUTF8Unsafe();
+    LOG(WARNING) << "Failed to delete " << temp_dir.AsUTF8Unsafe();
   }
 
   // No more tests to run, finish sequence.
@@ -700,17 +656,10 @@
     return;
   }
 
-  // Create a temporary directory for this task. This directory will hold the
-  // flags and results files for the child processes as well as their User Data
-  // dir, where appropriate. For platforms that support per-child temp dirs,
-  // this directory will also contain one subdirectory per child for that
-  // child's process-wide temp dir.
-  base::FilePath task_temp_dir;
-  CHECK(CreateNewTempDirectory(FilePath::StringType(), &task_temp_dir));
+  CreateNewTempDirectory(FilePath::StringType(), &temp_dir);
   bool post_to_current_runner = true;
   size_t batch_size = (batch_size_ == 0) ? tests_to_run_.size() : batch_size_;
 
-  int child_index = 0;
   while (post_to_current_runner && !tests_to_run_.empty()) {
     batch_size = std::min(batch_size, tests_to_run_.size());
     std::vector<std::string> batch(tests_to_run_.rbegin(),
@@ -719,29 +668,13 @@
     task_runner->PostTask(
         FROM_HERE,
         BindOnce(&TestLauncher::LaunchChildGTestProcess, Unretained(launcher_),
-                 ThreadTaskRunnerHandle::Get(), batch, task_temp_dir,
-                 CreateChildTempDirIfSupported(task_temp_dir, child_index++)));
+                 ThreadTaskRunnerHandle::Get(), batch, temp_dir));
     post_to_current_runner = ShouldReuseStateFromLastBatch(batch);
   }
   task_runner->PostTask(
       FROM_HERE,
       BindOnce(&TestRunner::ClearAndLaunchNext, Unretained(this),
-               ThreadTaskRunnerHandle::Get(), task_runner, task_temp_dir));
-}
-
-// Returns the number of files and directories in |dir|, or 0 if |dir| is empty.
-int CountItemsInDirectory(const FilePath& dir) {
-  if (dir.empty())
-    return 0;
-  int items = 0;
-  FileEnumerator file_enumerator(
-      dir, /*recursive=*/false,
-      FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
-  for (FilePath name = file_enumerator.Next(); !name.empty();
-       name = file_enumerator.Next()) {
-    ++items;
-  }
-  return items;
+               ThreadTaskRunnerHandle::Get(), task_runner, temp_dir));
 }
 
 }  // namespace
@@ -935,11 +868,10 @@
 void TestLauncher::LaunchChildGTestProcess(
     scoped_refptr<TaskRunner> task_runner,
     const std::vector<std::string>& test_names,
-    const FilePath& task_temp_dir,
-    const FilePath& child_temp_dir) {
+    const FilePath& temp_dir) {
   FilePath result_file;
-  CommandLine cmd_line = launcher_delegate_->GetCommandLine(
-      test_names, task_temp_dir, &result_file);
+  CommandLine cmd_line =
+      launcher_delegate_->GetCommandLine(test_names, temp_dir, &result_file);
 
   // Record the exact command line used to launch the child.
   CommandLine new_command_line(
@@ -948,9 +880,8 @@
   options.flags = launcher_delegate_->GetLaunchOptions();
 
   ChildProcessResults process_results = DoLaunchChildTestProcess(
-      new_command_line, child_temp_dir,
-      launcher_delegate_->GetTimeout() * test_names.size(), options,
-      redirect_stdio_, launcher_delegate_);
+      new_command_line, launcher_delegate_->GetTimeout() * test_names.size(),
+      options, redirect_stdio_, launcher_delegate_);
 
   // Invoke ProcessTestResults on the original thread, not
   // on a worker pool thread.
@@ -959,8 +890,7 @@
       BindOnce(&TestLauncher::ProcessTestResults, Unretained(this), test_names,
                result_file, process_results.output_file_contents,
                process_results.elapsed_time, process_results.exit_code,
-               process_results.was_timeout,
-               CountItemsInDirectory(child_temp_dir)));
+               process_results.was_timeout));
 }
 
 // Determines which result status will be assigned for missing test results.
@@ -990,8 +920,7 @@
     const std::string& output,
     TimeDelta elapsed_time,
     int exit_code,
-    bool was_timeout,
-    int leaked_items) {
+    bool was_timeout) {
   std::vector<TestResult> test_results;
   bool crashed = false;
   bool have_test_results =
@@ -1071,9 +1000,6 @@
     i.output_snippet = GetTestOutputSnippet(i, output);
   }
 
-  if (leaked_items)
-    results_tracker_.AddLeakedItems(leaked_items, test_names);
-
   launcher_delegate_->ProcessTestResults(final_results, elapsed_time);
 
   for (const auto& result : final_results)
diff --git a/base/test/launcher/test_launcher.h b/base/test/launcher/test_launcher.h
index 3100bc3..908f103 100644
--- a/base/test/launcher/test_launcher.h
+++ b/base/test/launcher/test_launcher.h
@@ -135,17 +135,14 @@
 
   // Launches a child process (assumed to be gtest-based binary) which runs
   // tests indicated by |test_names|.
-  // |task_runner| is used to post results back to the launcher on the main
-  // thread. |task_temp_dir| is used for child process files such as user data,
-  // result file, and flag_file. |child_temp_dir|, if not empty, specifies a
-  // directory (within task_temp_dir) that the child process will use as its
-  // process-wide temporary directory.
+  // |task_runner| is used to post results back to the launcher
+  // on the main thread. |temp_dir| is used for child process files,
+  // such as user data, result file, and flag_file.
   // virtual to mock in testing.
   virtual void LaunchChildGTestProcess(
       scoped_refptr<TaskRunner> task_runner,
       const std::vector<std::string>& test_names,
-      const FilePath& task_temp_dir,
-      const FilePath& child_temp_dir);
+      const FilePath& temp_dir);
 
   // Called when a test has finished running.
   void OnTestFinished(const TestResult& result);
@@ -209,15 +206,12 @@
   // EXPECT/ASSERT/DCHECK statements. Test launcher parses that
   // file to get additional information about test run (status,
   // error-messages, stack-traces and file/line for failures).
-  // |leaked_items| is the number of files and/or directories remaining in the
-  // child process's temporary directory upon its termination.
   void ProcessTestResults(const std::vector<std::string>& test_names,
                           const FilePath& result_file,
                           const std::string& output,
                           TimeDelta elapsed_time,
                           int exit_code,
-                          bool was_timeout,
-                          int leaked_items);
+                          bool was_timeout);
 
   // Make sure we don't accidentally call the wrong methods e.g. on the worker
   // pool thread.  Should be the first member so that it's destroyed last: when
diff --git a/base/test/launcher/test_launcher_unittest.cc b/base/test/launcher/test_launcher_unittest.cc
index 641b98d..0f70a643 100644
--- a/base/test/launcher/test_launcher_unittest.cc
+++ b/base/test/launcher/test_launcher_unittest.cc
@@ -65,11 +65,10 @@
 
   void CreateAndStartThreadPool(int parallel_jobs) override {}
 
-  MOCK_METHOD4(LaunchChildGTestProcess,
+  MOCK_METHOD3(LaunchChildGTestProcess,
                void(scoped_refptr<TaskRunner> task_runner,
                     const std::vector<std::string>& test_names,
-                    const FilePath& task_temp_dir,
-                    const FilePath& child_temp_dir));
+                    const FilePath& temp_dir));
 };
 
 // Simple TestLauncherDelegate mock to test TestLauncher flow.
@@ -186,7 +185,7 @@
 TEST_F(TestLauncherTest, EmptyTestSetPasses) {
   SetUpExpectCalls();
   using ::testing::_;
-  EXPECT_CALL(test_launcher, LaunchChildGTestProcess(_, _, _, _)).Times(0);
+  EXPECT_CALL(test_launcher, LaunchChildGTestProcess(_, _, _)).Times(0);
   EXPECT_TRUE(test_launcher.Run(command_line.get()));
 }
 
@@ -202,7 +201,7 @@
                                  _,
                                  testing::ElementsAreArray(tests_names.cbegin(),
                                                            tests_names.cend()),
-                                 _, _))
+                                 _))
       .WillOnce(::testing::DoAll(OnTestResult(&test_launcher, "Test.firstTest",
                                               TestResult::TEST_SUCCESS),
                                  OnTestResult(&test_launcher, "Test.secondTest",
@@ -221,7 +220,7 @@
                                  _,
                                  testing::ElementsAreArray(tests_names.cbegin(),
                                                            tests_names.cend()),
-                                 _, _))
+                                 _))
       .Times(1);
   EXPECT_TRUE(test_launcher.Run(command_line.get()));
 }
@@ -238,7 +237,7 @@
                                  _,
                                  testing::ElementsAreArray(tests_names.cbegin(),
                                                            tests_names.cend()),
-                                 _, _))
+                                 _))
       .WillOnce(OnTestResult(&test_launcher, "Test.firstTest",
                              TestResult::TEST_SUCCESS));
   EXPECT_TRUE(test_launcher.Run(command_line.get()));
@@ -256,7 +255,7 @@
                                  _,
                                  testing::ElementsAreArray(tests_names.cbegin(),
                                                            tests_names.cend()),
-                                 _, _))
+                                 _))
       .Times(1);
   EXPECT_TRUE(test_launcher.Run(command_line.get()));
 }
@@ -267,7 +266,7 @@
   SetUpExpectCalls();
   command_line->AppendSwitchASCII("gtest_repeat", "2");
   using ::testing::_;
-  EXPECT_CALL(test_launcher, LaunchChildGTestProcess(_, _, _, _))
+  EXPECT_CALL(test_launcher, LaunchChildGTestProcess(_, _, _))
       .Times(2)
       .WillRepeatedly(OnTestResult(&test_launcher, "Test.firstTest",
                                    TestResult::TEST_SUCCESS));
@@ -285,7 +284,7 @@
                                  _,
                                  testing::ElementsAreArray(tests_names.cbegin(),
                                                            tests_names.cend()),
-                                 _, _))
+                                 _))
       .WillOnce(OnTestResult(&test_launcher, "Test.firstTest",
                              TestResult::TEST_FAILURE))
       .WillOnce(OnTestResult(&test_launcher, "Test.firstTest",
@@ -305,7 +304,7 @@
                                  _,
                                  testing::ElementsAreArray(tests_names.cbegin(),
                                                            tests_names.cend()),
-                                 _, _))
+                                 _))
       .Times(3)
       .WillRepeatedly(OnTestResult(&test_launcher, "Test.firstTest",
                                    TestResult::TEST_FAILURE));
@@ -322,7 +321,7 @@
       GenerateTestResult("Test.PRE_firstTest", TestResult::TEST_FAILURE),
       GenerateTestResult("Test.firstTest", TestResult::TEST_SUCCESS)};
   using ::testing::_;
-  EXPECT_CALL(test_launcher, LaunchChildGTestProcess(_, _, _, _))
+  EXPECT_CALL(test_launcher, LaunchChildGTestProcess(_, _, _))
       .WillOnce(::testing::DoAll(
           OnTestResult(&test_launcher, "Test.PRE_PRE_firstTest",
                        TestResult::TEST_SUCCESS),
@@ -335,7 +334,7 @@
                                  _,
                                  testing::ElementsAreArray(tests_names.cbegin(),
                                                            tests_names.cend()),
-                                 _, _))
+                                 _))
       .WillOnce(OnTestResult(&test_launcher, "Test.PRE_PRE_firstTest",
                              TestResult::TEST_SUCCESS));
   tests_names = {"Test.PRE_firstTest"};
@@ -343,7 +342,7 @@
                                  _,
                                  testing::ElementsAreArray(tests_names.cbegin(),
                                                            tests_names.cend()),
-                                 _, _))
+                                 _))
       .WillOnce(OnTestResult(&test_launcher, "Test.PRE_firstTest",
                              TestResult::TEST_SUCCESS));
   tests_names = {"Test.firstTest"};
@@ -351,7 +350,7 @@
                                  _,
                                  testing::ElementsAreArray(tests_names.cbegin(),
                                                            tests_names.cend()),
-                                 _, _))
+                                 _))
       .WillOnce(OnTestResult(&test_launcher, "Test.firstTest",
                              TestResult::TEST_SUCCESS));
   EXPECT_TRUE(test_launcher.Run(command_line.get()));
@@ -373,7 +372,7 @@
                                  _,
                                  testing::ElementsAreArray(tests_names.cbegin(),
                                                            tests_names.cend()),
-                                 _, _))
+                                 _))
       .WillOnce(::testing::DoAll(
           OnTestResult(&test_launcher, "Test.firstTest",
                        TestResult::TEST_SUCCESS),
@@ -395,7 +394,7 @@
                                  _,
                                  testing::ElementsAreArray(tests_names.cbegin(),
                                                            tests_names.cend()),
-                                 _, _))
+                                 _))
       .Times(1);
   EXPECT_TRUE(test_launcher.Run(command_line.get()));
 }
@@ -413,7 +412,7 @@
   SetUpExpectCalls();
   command_line->AppendSwitchASCII("test-launcher-print-test-stdio", "always");
   using ::testing::_;
-  EXPECT_CALL(test_launcher, LaunchChildGTestProcess(_, _, _, _))
+  EXPECT_CALL(test_launcher, LaunchChildGTestProcess(_, _, _))
       .WillOnce(OnTestResult(&test_launcher, "Test.firstTest",
                              TestResult::TEST_SUCCESS));
   EXPECT_TRUE(test_launcher.Run(command_line.get()));
@@ -525,7 +524,7 @@
                          TimeDelta::FromMilliseconds(50), "output_second");
 
   using ::testing::_;
-  EXPECT_CALL(test_launcher, LaunchChildGTestProcess(_, _, _, _))
+  EXPECT_CALL(test_launcher, LaunchChildGTestProcess(_, _, _))
       .Times(2)
       .WillRepeatedly(
           ::testing::DoAll(OnTestResult(&test_launcher, first_result),
@@ -581,7 +580,7 @@
                          TimeDelta::FromMilliseconds(50), "output_second");
 
   using ::testing::_;
-  EXPECT_CALL(test_launcher, LaunchChildGTestProcess(_, _, _, _))
+  EXPECT_CALL(test_launcher, LaunchChildGTestProcess(_, _, _))
       .WillOnce(OnTestResult(&test_launcher, test_result));
   EXPECT_TRUE(test_launcher.Run(command_line.get()));
 
diff --git a/base/test/launcher/test_results_tracker.cc b/base/test/launcher/test_results_tracker.cc
index 37c31ac3..8522db4 100644
--- a/base/test/launcher/test_results_tracker.cc
+++ b/base/test/launcher/test_results_tracker.cc
@@ -22,7 +22,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/gtest_util.h"
 #include "base/test/launcher/test_launcher.h"
-#include "base/test/test_switches.h"
 #include "base/time/time.h"
 #include "base/values.h"
 
@@ -167,9 +166,6 @@
     return false;
   }
 
-  print_temp_leaks_ =
-      command_line.HasSwitch(switches::kTestLauncherPrintTempLeaks);
-
   if (!command_line.HasSwitch(kGTestOutputFlag))
     return true;
 
@@ -274,13 +270,6 @@
   aggregate_test_result.test_results.push_back(result);
 }
 
-void TestResultsTracker::AddLeakedItems(
-    int count,
-    const std::vector<std::string>& test_names) {
-  DCHECK(count);
-  per_iteration_data_.back().leaked_temp_items.emplace_back(count, test_names);
-}
-
 void TestResultsTracker::GeneratePlaceholderIteration() {
   CHECK(thread_checker_.CalledOnValidThread());
 
@@ -327,13 +316,6 @@
              "had unknown result");
   PrintTests(tests_by_status[TestResult::TEST_NOT_RUN].begin(),
              tests_by_status[TestResult::TEST_NOT_RUN].end(), "not run");
-
-  if (print_temp_leaks_) {
-    for (const auto& leaking_tests :
-         per_iteration_data_.back().leaked_temp_items) {
-      PrintLeaks(leaking_tests.first, leaking_tests.second);
-    }
-  }
 }
 
 void TestResultsTracker::PrintSummaryOfAllIterations() const {
@@ -592,16 +574,6 @@
   fflush(stdout);
 }
 
-void TestResultsTracker::PrintLeaks(
-    int count,
-    const std::vector<std::string>& test_names) const {
-  fprintf(stdout,
-          "ERROR: %d files and/or directories were left behind in the temporary"
-          " directory by one or more of these tests: %s\n",
-          count, JoinString(test_names, ":").c_str());
-  fflush(stdout);
-}
-
 TestResultsTracker::AggregateTestResult::AggregateTestResult() = default;
 
 TestResultsTracker::AggregateTestResult::AggregateTestResult(
diff --git a/base/test/launcher/test_results_tracker.h b/base/test/launcher/test_results_tracker.h
index 7201ab48..61f29cd 100644
--- a/base/test/launcher/test_results_tracker.h
+++ b/base/test/launcher/test_results_tracker.h
@@ -61,10 +61,6 @@
   // Adds |result| to the stored test results.
   void AddTestResult(const TestResult& result);
 
-  // Adds to the current iteration the fact that |count| items were leaked by
-  // one or more tests in |test_names| in its temporary directory.
-  void AddLeakedItems(int count, const std::vector<std::string>& test_names);
-
   // Even when no iterations have occurred, we still want to generate output
   // data with "NOTRUN" status for each test. This method generates a
   // placeholder iteration. The first iteration will overwrite the data in the
@@ -105,7 +101,6 @@
   void PrintTests(InputIterator first,
                   InputIterator last,
                   const std::string& description) const;
-  void PrintLeaks(int count, const std::vector<std::string>& test_names) const;
 
   struct AggregateTestResult {
     AggregateTestResult();
@@ -123,9 +118,6 @@
     // Aggregate test results grouped by full test name.
     typedef std::map<std::string, AggregateTestResult> ResultsMap;
     ResultsMap results;
-
-    // A sequence of tests that leaked files/dirs in their temp directory.
-    std::vector<std::pair<int, std::vector<std::string>>> leaked_temp_items;
   };
 
   struct CodeLocation {
@@ -138,9 +130,6 @@
 
   ThreadChecker thread_checker_;
 
-  // Print tests that leak files and/or directories in their temp dir.
-  bool print_temp_leaks_ = false;
-
   // Set of global tags, i.e. strings indicating conditions that apply to
   // the entire test run.
   std::set<std::string> global_tags_;
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc
index ec0800c..039a69c 100644
--- a/base/test/launcher/unit_test_launcher.cc
+++ b/base/test/launcher/unit_test_launcher.cc
@@ -104,11 +104,7 @@
           "    Sets the shard index to run to N (from 0 to TOTAL - 1).\n"
           "\n"
           "  --dont-use-job-objects\n"
-          "    Avoids using job objects in Windows.\n"
-          "\n"
-          "  --test-launcher-print-temp-leaks\n"
-          "    Prints information about leaked files and/or directories in\n"
-          "    child process's temporary directories (Windows and macOS).\n");
+          "    Avoids using job objects in Windows.\n");
   fflush(stdout);
 }
 
diff --git a/base/test/test_switches.cc b/base/test/test_switches.cc
index ec022ced..f1d04d5 100644
--- a/base/test/test_switches.cc
+++ b/base/test/test_switches.cc
@@ -58,11 +58,6 @@
 const char switches::kTestLauncherSummaryOutput[] =
     "test-launcher-summary-output";
 
-// Causes the test launcher to print information about leaked files and/or
-// directories in child process's temporary directories.
-const char switches::kTestLauncherPrintTempLeaks[] =
-    "test-launcher-print-temp-leaks";
-
 // Flag controlling when test stdio is displayed as part of the launcher's
 // standard output.
 const char switches::kTestLauncherPrintTestStdio[] =
diff --git a/base/test/test_switches.h b/base/test/test_switches.h
index 9e2e627..2d6b5f4 100644
--- a/base/test/test_switches.h
+++ b/base/test/test_switches.h
@@ -25,7 +25,6 @@
 extern const char kTestLauncherRetryLimit[];
 extern const char kIsolatedScriptTestLauncherRetryLimit[];
 extern const char kTestLauncherSummaryOutput[];
-extern const char kTestLauncherPrintTempLeaks[];
 extern const char kTestLauncherPrintTestStdio[];
 extern const char kTestLauncherPrintWritablePath[];
 extern const char kTestLauncherShardIndex[];
diff --git a/base/third_party/symbolize/README.chromium b/base/third_party/symbolize/README.chromium
index 152b5f7f..12075b0 100644
--- a/base/third_party/symbolize/README.chromium
+++ b/base/third_party/symbolize/README.chromium
@@ -3,7 +3,7 @@
 License: BSD
 
 The following files are copied AS-IS from:
-https://github.com/google/glog/tree/5d46e1bcfc92bf06a9ca3b3f1c5bb1dc024d9ecd
+https://github.com/google/glog/tree/130a3e10de248344cdaeda54aed4c8a5ad7cedac
 
 - demangle.cc
 - demangle.h
diff --git a/base/third_party/symbolize/symbolize.cc b/base/third_party/symbolize/symbolize.cc
index 1ffc6079..76a1b0f 100644
--- a/base/third_party/symbolize/symbolize.cc
+++ b/base/third_party/symbolize/symbolize.cc
@@ -110,7 +110,9 @@
 
 #if defined(__ELF__)
 
+#if defined(HAVE_DLFCN_H)
 #include <dlfcn.h>
+#endif
 #if defined(OS_OPENBSD)
 #include <sys/exec_elf.h>
 #else
@@ -310,6 +312,7 @@
         ssize_t len1 = ReadFromOffset(fd, out, out_size,
                                       strtab->sh_offset + symbol.st_name);
         if (len1 <= 0 || memchr(out, '\0', out_size) == NULL) {
+          memset(out, 0, out_size);
           return false;
         }
         return true;  // Obtained the symbol name.
@@ -372,7 +375,7 @@
   explicit FileDescriptor(int fd) : fd_(fd) {}
   ~FileDescriptor() {
     if (fd_ >= 0) {
-      NO_INTR(close(fd_));
+      close(fd_);
     }
   }
   int get() { return fd_; }
@@ -781,9 +784,10 @@
                                                              out_size - 1);
   }
 
+  FileDescriptor wrapped_object_fd(object_fd);
+
 #if defined(PRINT_UNSYMBOLIZED_STACK_TRACES)
   {
-    FileDescriptor wrapped_object_fd(object_fd);
 #else
   // Check whether a file name was returned.
   if (object_fd < 0) {
@@ -802,7 +806,6 @@
     // Failed to determine the object file containing PC.  Bail out.
     return false;
   }
-  FileDescriptor wrapped_object_fd(object_fd);
   int elf_type = FileGetElfType(wrapped_object_fd.get());
   if (elf_type == -1) {
     return false;
@@ -822,6 +825,17 @@
   }
   if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
                                out, out_size, base_address)) {
+    if (out[1] && !g_symbolize_callback) {
+      // The object file containing PC was opened successfully however the
+      // symbol was not found. The object may have been stripped. This is still
+      // considered success because the object file name and offset are known
+      // and tools like asan_symbolize.py can be used for the symbolization.
+      out[out_size - 1] = '\0';  // Making sure |out| is always null-terminated.
+      SafeAppendString("+0x", out, out_size);
+      SafeAppendHexNumber(pc0 - base_address, out, out_size);
+      SafeAppendString(")", out, out_size);
+      return true;
+    }
     return false;
   }
 
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 6971faf..0ee88c8 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1366,7 +1366,6 @@
   "java/src/org/chromium/chrome/browser/sessions/SessionTabHelper.java",
   "java/src/org/chromium/chrome/browser/settings/ButtonPreference.java",
   "java/src/org/chromium/chrome/browser/settings/ChromeBaseCheckBoxPreference.java",
-  "java/src/org/chromium/chrome/browser/settings/ChromeBasePreference.java",
   "java/src/org/chromium/chrome/browser/settings/ChromeSwitchPreference.java",
   "java/src/org/chromium/chrome/browser/settings/ExpandablePreferenceGroup.java",
   "java/src/org/chromium/chrome/browser/settings/HyperlinkPreference.java",
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceActionHandler.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceActionHandler.java
index 09bf3ad..bbfb2a05 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceActionHandler.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceActionHandler.java
@@ -35,6 +35,16 @@
     }
 
     @Override
+    public boolean canOpenUrlInIncognitoMode() {
+        return false;
+    }
+
+    @Override
+    public boolean canOpenUrlInNewTab() {
+        return false;
+    }
+
+    @Override
     public void learnMore() {}
 
     @Override
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
index f9c14213a..08b390a 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
@@ -613,7 +613,7 @@
     static boolean isShowingTabsInMRUOrder() {
         String feature = ChromeFeatureList.getFieldTrialParamByFeature(
                 ChromeFeatureList.START_SURFACE_ANDROID, "start_surface_variation");
-        return feature.equals("twopanes") || feature.equals("single");
+        return feature.equals("twopanes");
     }
 
     /**
diff --git a/chrome/android/java/res/values-v21/styles.xml b/chrome/android/java/res/values-v21/styles.xml
index 3b3ef7c..b6bccb51 100644
--- a/chrome/android/java/res/values-v21/styles.xml
+++ b/chrome/android/java/res/values-v21/styles.xml
@@ -32,29 +32,6 @@
         <item name="android:paddingEnd">0dp</item>
     </style>
 
-    <style name="PreferenceLayoutCompat">
-        <item name="android:paddingStart">?android:attr/listPreferredItemPaddingStart</item>
-        <item name="android:paddingEnd">?android:attr/listPreferredItemPaddingEnd</item>
-        <item name="android:minHeight">?android:attr/listPreferredItemHeightSmall</item>
-    </style>
-
-    <style name="PreferenceDescriptionCompat">
-        <item name="android:paddingTop">16dp</item>
-        <item name="android:paddingBottom">16dp</item>
-    </style>
-
-    <style name="PreferenceWidgetCompat">
-        <item name="android:paddingStart">16dp</item>
-    </style>
-
-    <style name="PreferenceTitle">
-        <item name="android:ellipsize">end</item>
-        <item name="android:singleLine">true</item>
-        <item name="android:textAppearance">?android:attr/textAppearanceListItem</item>
-    </style>
-    <style name="PreferenceSummary">
-        <item name="android:textAppearance">@style/TextAppearance.BlackBody</item>
-    </style>
     <style name="PreferenceLayoutBase">
         <item name="android:background">?android:attr/activatedBackgroundIndicator</item>
         <item name="android:minHeight">?android:attr/listPreferredItemHeightSmall</item>
diff --git a/chrome/android/java/res/values/attrs.xml b/chrome/android/java/res/values/attrs.xml
index ec98a88..4ccceddb 100644
--- a/chrome/android/java/res/values/attrs.xml
+++ b/chrome/android/java/res/values/attrs.xml
@@ -14,11 +14,6 @@
         <attr name="helpContext" format="string" />
     </declare-styleable>
 
-    <declare-styleable name="ChromeBasePreference">
-        <!-- The tint color for the icon set by android:icon. -->
-        <attr name="iconTint" format="color" />
-    </declare-styleable>
-
     <declare-styleable name="ChromeSwitchPreference">
         <!-- Prevents the summary text from being styled like title text in the
              case that the title is empty. -->
diff --git a/chrome/android/java/res/values/styles.xml b/chrome/android/java/res/values/styles.xml
index 50826df..5af3d88e 100644
--- a/chrome/android/java/res/values/styles.xml
+++ b/chrome/android/java/res/values/styles.xml
@@ -212,26 +212,6 @@
         <item name="android:layout">@layout/preference_compat</item>
     </style>
 
-    <!-- TODO(crbug.com/971791): The asymmetric start and end paddings here preserve the same
-         overall padding as the pre-support library custom preference layout. Following migration to
-         the support library preferences, we should investigate simplifying these styles.-->
-    <style name="PreferenceLayoutCompat">
-        <item name="android:paddingStart">8dp</item>
-        <item name="android:paddingEnd">10dp</item>
-        <item name="android:minHeight">?android:attr/listPreferredItemHeight</item>
-        <item name="android:background">?android:attr/selectableItemBackground</item>
-    </style>
-
-    <style name="PreferenceDescriptionCompat">
-        <item name="android:paddingTop">6dp</item>
-        <item name="android:paddingBottom">6dp</item>
-        <item name="android:paddingEnd">8dp</item>
-    </style>
-
-    <style name="PreferenceWidgetCompat">
-        <item name="android:minWidth">48dp</item>
-    </style>
-
     <style name="SettingsFragmentList">
         <item name="android:paddingStart">@dimen/pref_list_padding_kitkat</item>
         <item name="android:paddingEnd">@dimen/pref_list_padding_kitkat</item>
@@ -255,18 +235,6 @@
     <style name="SettingsActionBarModern" parent="@style/Widget.AppCompat.Light.ActionBar.Solid">
       <item name="titleTextStyle">@style/TextAppearance.BlackHeadline</item>
     </style>
-    <style name="TextAppearance.PreferenceMediumText">
-        <item name="android:textSize">18sp</item>
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
-    </style>
-    <style name="PreferenceTitle">
-        <item name="android:ellipsize">end</item>
-        <item name="android:singleLine">true</item>
-        <item name="android:textAppearance">@style/TextAppearance.PreferenceMediumText</item>
-    </style>
-    <style name="PreferenceSummary">
-        <item name="android:textAppearance">@style/TextAppearance.BlackBody</item>
-    </style>
     <style name="PreferenceScreenLayout">
         <item name="android:paddingTop">16dp</item>
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
index ac9bb86b..126456d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -144,6 +144,7 @@
                 ProductConfig.COMPRESSED_LOCALES, ProductConfig.UNCOMPRESSED_LOCALES);
         LibraryLoader.getInstance().setLinkerImplementation(
                 ProductConfig.USE_CHROMIUM_LINKER, ProductConfig.USE_MODERN_LINKER);
+        LibraryLoader.getInstance().enableJniChecks();
 
         if (isBrowserProcess) {
             TraceEvent.end("ChromeApplication.attachBaseContext");
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackupAgent.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackupAgent.java
index 7362760..7c99cf7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackupAgent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackupAgent.java
@@ -25,7 +25,6 @@
 import org.chromium.chrome.browser.init.AsyncInitTaskRunner;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
-import org.chromium.chrome.browser.settings.privacy.PrivacyPreferencesManager;
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.ChromeSigninController;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
@@ -92,7 +91,7 @@
             ChromePreferenceKeys.FIRST_RUN_FLOW_COMPLETE,
             ChromePreferenceKeys.FIRST_RUN_LIGHTWEIGHT_FLOW_COMPLETE,
             ChromePreferenceKeys.FIRST_RUN_FLOW_SIGNIN_SETUP,
-            PrivacyPreferencesManager.PREF_METRICS_REPORTING,
+            ChromePreferenceKeys.PRIVACY_METRICS_REPORTING,
     };
 
     // Timeout for running the background tasks, needs to be quite long since they may be doing
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 728f2ad..603cad0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -677,7 +677,11 @@
                 // newtab button on the toolbar.
                 getCurrentTabCreator().launchNTP();
                 mLocaleManager.showSearchEnginePromoIfNeeded(ChromeTabbedActivity.this, null);
-                RecordUserAction.record("MobileToolbarStackViewNewTab");
+                if (getTabModelSelector().isIncognitoSelected()) {
+                    RecordUserAction.record("MobileToolbarStackViewNewIncognitoTab");
+                } else {
+                    RecordUserAction.record("MobileToolbarStackViewNewTab");
+                }
                 if (getToolbarManager().isBottomToolbarVisible()) {
                     RecordUserAction.record("MobileBottomToolbarNewTabButton");
                 } else {
@@ -996,9 +1000,12 @@
     }
 
     private boolean shouldShowTabSwitcherOnStart() {
+        if (!isMainIntentFromLauncher(getIntent())) return false;
+
         long lastBackgroundedTimeMillis = mInactivityTracker.getLastBackgroundedTimeMs();
-        return ReturnToChromeExperimentsUtil.shouldShowTabSwitcher(lastBackgroundedTimeMillis)
-                && isMainIntentFromLauncher(getIntent());
+        return (ReturnToChromeExperimentsUtil.shouldShowStartSurfaceAsTheHomePage()
+                       && getTabModelSelector().getTotalTabCount() <= 0)
+                || ReturnToChromeExperimentsUtil.shouldShowTabSwitcher(lastBackgroundedTimeMillis);
     }
 
     private boolean isMainIntentFromLauncher(Intent intent) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/notification/UpdateNotificationServiceBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/notification/UpdateNotificationServiceBridge.java
index e3a1512..684fa43 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/notification/UpdateNotificationServiceBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/notification/UpdateNotificationServiceBridge.java
@@ -34,6 +34,8 @@
 public class UpdateNotificationServiceBridge implements UpdateNotificationController, Destroyable {
     private static final String PREF_UPDATE_NOTIFICATION_THROTTLE_INTERVAL_KEY =
             "pref_update_notification_throttle_interval_key";
+    private static final String PREF_UPDATE_NOTIFICATION_USER_DISMISS_COUNT_KEY =
+            "pref_update_notification_user_dismiss_count_key";
 
     private final Callback<UpdateStatusProvider.UpdateStatus> mObserver = status -> {
         mUpdateStatus = status;
@@ -122,4 +124,27 @@
         editor.putLong(PREF_UPDATE_NOTIFICATION_THROTTLE_INTERVAL_KEY, interval);
         editor.apply();
     }
+
+    /**
+     * Gets the number of users consecutive dimiss action on update notification from {@link
+     * SharedPreferences}.
+     */
+    @CalledByNative
+    public static int getUserDismissCount() {
+        SharedPreferences preferences = OmahaBase.getSharedPreferences();
+        return preferences.getInt(PREF_UPDATE_NOTIFICATION_USER_DISMISS_COUNT_KEY, 0);
+    }
+
+    /**
+     * Updates the number to record users consecutive dimiss action on update notification in {@link
+     * SharedPreferences}.
+     * @param count A number of users consecutive dimiss action.
+     */
+    @CalledByNative
+    private static void updateUserDismissCount(int count) {
+        SharedPreferences preferences = OmahaBase.getSharedPreferences();
+        SharedPreferences.Editor editor = preferences.edit();
+        editor.putInt(PREF_UPDATE_NOTIFICATION_USER_DISMISS_COUNT_KEY, count);
+        editor.apply();
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/privacy/PrivacyPreferencesManager.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/privacy/PrivacyPreferencesManager.java
index cacc397..9040219 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/privacy/PrivacyPreferencesManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/privacy/PrivacyPreferencesManager.java
@@ -6,7 +6,6 @@
 
 import android.annotation.SuppressLint;
 import android.content.Context;
-import android.content.SharedPreferences;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 
@@ -18,6 +17,8 @@
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.device.DeviceClassManager;
+import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
+import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.chrome.browser.survey.SurveyController;
 import org.chromium.components.minidump_uploader.util.CrashReportingPermissionManager;
 import org.chromium.components.minidump_uploader.util.NetworkPermissionUtil;
@@ -27,23 +28,16 @@
  * Reads, writes, and migrates preferences related to network usage and privacy.
  */
 public class PrivacyPreferencesManager implements CrashReportingPermissionManager{
-    public static final String PREF_METRICS_REPORTING = "metrics_reporting";
-    private static final String PREF_METRICS_IN_SAMPLE = "in_metrics_sample";
-    private static final String PREF_NETWORK_PREDICTIONS = "network_predictions";
-    private static final String PREF_BANDWIDTH_OLD = "prefetch_bandwidth";
-    private static final String PREF_BANDWIDTH_NO_CELLULAR_OLD = "prefetch_bandwidth_no_cellular";
-    private static final String ALLOW_PRERENDER_OLD = "allow_prefetch";
-
     @SuppressLint("StaticFieldLeak")
     private static PrivacyPreferencesManager sInstance;
 
     private final Context mContext;
-    private final SharedPreferences mSharedPreferences;
+    private final SharedPreferencesManager mPrefs;
 
     @VisibleForTesting
     PrivacyPreferencesManager(Context context) {
         mContext = context;
-        mSharedPreferences = ContextUtils.getAppSharedPreferences();
+        mPrefs = SharedPreferencesManager.getInstance();
     }
 
     public static PrivacyPreferencesManager getInstance() {
@@ -65,7 +59,7 @@
         // See if PREF_NETWORK_PREDICTIONS is an old boolean value.
         boolean predictionOptionIsBoolean = false;
         try {
-            mSharedPreferences.getString(PREF_NETWORK_PREDICTIONS, "");
+            mPrefs.readString(ChromePreferenceKeys.PRIVACY_NETWORK_PREDICTIONS, "");
         } catch (ClassCastException ex) {
             predictionOptionIsBoolean = true;
         }
@@ -78,8 +72,8 @@
 
         // Nothing to do if the old preferences are unset.
         if (!predictionOptionIsBoolean
-                && !mSharedPreferences.contains(PREF_BANDWIDTH_OLD)
-                && !mSharedPreferences.contains(PREF_BANDWIDTH_NO_CELLULAR_OLD)) {
+                && !mPrefs.contains(ChromePreferenceKeys.PRIVACY_BANDWIDTH_OLD)
+                && !mPrefs.contains(ChromePreferenceKeys.PRIVACY_BANDWIDTH_NO_CELLULAR_OLD)) {
             return;
         }
 
@@ -89,17 +83,18 @@
         final String prefBandwidthDefault =
                 BandwidthType.title(BandwidthType.Type.PRERENDER_ON_WIFI);
         final String prefBandwidth =
-                mSharedPreferences.getString(PREF_BANDWIDTH_OLD, prefBandwidthDefault);
+                mPrefs.readString(ChromePreferenceKeys.PRIVACY_BANDWIDTH_OLD, prefBandwidthDefault);
         boolean prefBandwidthNoCellularDefault = true;
-        boolean prefBandwidthNoCellular = mSharedPreferences.getBoolean(
-                PREF_BANDWIDTH_NO_CELLULAR_OLD, prefBandwidthNoCellularDefault);
+        boolean prefBandwidthNoCellular =
+                mPrefs.readBoolean(ChromePreferenceKeys.PRIVACY_BANDWIDTH_NO_CELLULAR_OLD,
+                        prefBandwidthNoCellularDefault);
 
         if (!(prefBandwidthDefault.equals(prefBandwidth))
                 || (prefBandwidthNoCellular != prefBandwidthNoCellularDefault)) {
             boolean newValue = true;
             // Observe PREF_BANDWIDTH on mobile network capable devices.
             if (isMobileNetworkCapable()) {
-                if (mSharedPreferences.contains(PREF_BANDWIDTH_OLD)) {
+                if (mPrefs.contains(ChromePreferenceKeys.PRIVACY_BANDWIDTH_OLD)) {
                     @BandwidthType.Type
                     int prefetchBandwidthTypePref =
                             BandwidthType.getBandwidthFromTitle(prefBandwidth);
@@ -112,7 +107,7 @@
                 }
             // Observe PREF_BANDWIDTH_NO_CELLULAR on devices without mobile network.
             } else {
-                if (mSharedPreferences.contains(PREF_BANDWIDTH_NO_CELLULAR_OLD)) {
+                if (mPrefs.contains(ChromePreferenceKeys.PRIVACY_BANDWIDTH_NO_CELLULAR_OLD)) {
                     newValue = prefBandwidthNoCellular;
                 }
             }
@@ -121,27 +116,26 @@
         }
 
         // Delete old sharedPreferences.
-        SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit();
+
         // Delete PREF_BANDWIDTH and PREF_BANDWIDTH_NO_CELLULAR: just migrated these options.
-        if (mSharedPreferences.contains(PREF_BANDWIDTH_OLD)) {
-            sharedPreferencesEditor.remove(PREF_BANDWIDTH_OLD);
+        if (mPrefs.contains(ChromePreferenceKeys.PRIVACY_BANDWIDTH_OLD)) {
+            mPrefs.removeKey(ChromePreferenceKeys.PRIVACY_BANDWIDTH_OLD);
         }
-        if (mSharedPreferences.contains(PREF_BANDWIDTH_NO_CELLULAR_OLD)) {
-            sharedPreferencesEditor.remove(PREF_BANDWIDTH_NO_CELLULAR_OLD);
+        if (mPrefs.contains(ChromePreferenceKeys.PRIVACY_BANDWIDTH_NO_CELLULAR_OLD)) {
+            mPrefs.removeKey(ChromePreferenceKeys.PRIVACY_BANDWIDTH_NO_CELLULAR_OLD);
         }
         // Also delete ALLOW_PRERENDER, which was updated based on PREF_BANDWIDTH[_NO_CELLULAR] and
         // network connectivity type, therefore does not carry additional information.
-        if (mSharedPreferences.contains(ALLOW_PRERENDER_OLD)) {
-            sharedPreferencesEditor.remove(ALLOW_PRERENDER_OLD);
+        if (mPrefs.contains(ChromePreferenceKeys.PRIVACY_ALLOW_PRERENDER_OLD)) {
+            mPrefs.removeKey(ChromePreferenceKeys.PRIVACY_ALLOW_PRERENDER_OLD);
         }
         // Delete bool PREF_NETWORK_PREDICTIONS so that string values can be stored. Note that this
         // SharedPreference carries no information, because it used to be overwritten by
         // kNetworkPredictionEnabled on startup, and now it is overwritten by
         // kNetworkPredictionOptions on startup.
-        if (mSharedPreferences.contains(PREF_NETWORK_PREDICTIONS)) {
-            sharedPreferencesEditor.remove(PREF_NETWORK_PREDICTIONS);
+        if (mPrefs.contains(ChromePreferenceKeys.PRIVACY_NETWORK_PREDICTIONS)) {
+            mPrefs.removeKey(ChromePreferenceKeys.PRIVACY_NETWORK_PREDICTIONS);
         }
-        sharedPreferencesEditor.apply();
     }
 
     protected boolean isNetworkAvailable() {
@@ -179,7 +173,7 @@
      * @param enabled A boolean corresponding whether usage and crash reports uploads are allowed.
      */
     public void setUsageAndCrashReporting(boolean enabled) {
-        mSharedPreferences.edit().putBoolean(PREF_METRICS_REPORTING, enabled).apply();
+        mPrefs.writeBoolean(ChromePreferenceKeys.PRIVACY_METRICS_REPORTING, enabled);
         syncUsageAndCrashReportingPrefs();
         if (!enabled) {
             SurveyController.getInstance().clearCache(ContextUtils.getApplicationContext());
@@ -204,7 +198,7 @@
      * {@link org.chromium.chrome.browser.metrics.UmaUtils#isClientInMetricsSample} for details.
      */
     public void setClientInMetricsSample(boolean inSample) {
-        mSharedPreferences.edit().putBoolean(PREF_METRICS_IN_SAMPLE, inSample).apply();
+        mPrefs.writeBoolean(ChromePreferenceKeys.PRIVACY_METRICS_IN_SAMPLE, inSample);
     }
 
     /**
@@ -218,7 +212,7 @@
         // The default value is true to avoid sampling out crashes that occur before native code has
         // been initialized on first run. We'd rather have some extra crashes than none from that
         // time.
-        return mSharedPreferences.getBoolean(PREF_METRICS_IN_SAMPLE, true);
+        return mPrefs.readBoolean(ChromePreferenceKeys.PRIVACY_METRICS_IN_SAMPLE, true);
     }
 
     /**
@@ -242,7 +236,7 @@
      */
     @Override
     public boolean isUsageAndCrashReportingPermittedByUser() {
-        return mSharedPreferences.getBoolean(PREF_METRICS_REPORTING, false);
+        return mPrefs.readBoolean(ChromePreferenceKeys.PRIVACY_METRICS_REPORTING, false);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index d49409f..dce31f8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -250,7 +250,9 @@
 
     private int mCurrentOrientation;
 
-    /** Runnable for the home button when Start Surface home page is enabled. */
+    /**
+     * Runnable for the home and search accelerator button when Start Surface home page is enabled.
+     */
     private Supplier<Boolean> mShowStartSurfaceSupplier;
 
     /**
@@ -801,6 +803,11 @@
         final OnClickListener searchAcceleratorListener = v -> {
             recordBottomToolbarUseForIPH();
             ACCELERATOR_BUTTON_TAP_ACTION.record();
+
+            // Only switch to HomePage when overview is showing.
+            if (mOverviewModeBehavior.overviewVisible()) {
+                mShowStartSurfaceSupplier.get();
+            }
             setUrlBarFocus(true, LocationBar.OmniboxFocusReason.ACCELERATOR_TAP);
         };
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/settings/privacy/PrivacyPreferencesManagerNativeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/privacy/PrivacyPreferencesManagerNativeTest.java
index b07e2fa1..7ef585e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/settings/privacy/PrivacyPreferencesManagerNativeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/privacy/PrivacyPreferencesManagerNativeTest.java
@@ -21,6 +21,7 @@
 import org.chromium.base.test.util.AdvancedMockContext;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.test.ChromeBrowserTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
@@ -47,7 +48,7 @@
 
         // Setup prefs to be out of sync.
         PrivacyPreferencesManager.getInstance().setMetricsReportingEnabled(false);
-        pref.edit().putBoolean(PrivacyPreferencesManager.PREF_METRICS_REPORTING, true).apply();
+        pref.edit().putBoolean(ChromePreferenceKeys.PRIVACY_METRICS_REPORTING, true).apply();
 
         preferenceManager.syncUsageAndCrashReportingPrefs();
         Assert.assertTrue("Native preference should be True ",
@@ -67,13 +68,12 @@
         PrivacyPreferencesManager preferenceManager = new PrivacyPreferencesManager(context);
 
         preferenceManager.setUsageAndCrashReporting(true);
-        Assert.assertTrue(pref.getBoolean(PrivacyPreferencesManager.PREF_METRICS_REPORTING, false));
+        Assert.assertTrue(pref.getBoolean(ChromePreferenceKeys.PRIVACY_METRICS_REPORTING, false));
         Assert.assertTrue("Native preference should be True ",
                 PrivacyPreferencesManager.getInstance().isMetricsReportingEnabled());
 
         preferenceManager.setUsageAndCrashReporting(false);
-        Assert.assertFalse(
-                pref.getBoolean(PrivacyPreferencesManager.PREF_METRICS_REPORTING, false));
+        Assert.assertFalse(pref.getBoolean(ChromePreferenceKeys.PRIVACY_METRICS_REPORTING, false));
         Assert.assertFalse("Native preference should be False ",
                 PrivacyPreferencesManager.getInstance().isMetricsReportingEnabled());
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNavigationTest.java
index a8de66b..5a14cd00 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNavigationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNavigationTest.java
@@ -704,9 +704,8 @@
                 UserFriendlyElementName.SUGGESTION_BOX, true /* visible */,
                 () -> { NativeUiUtils.inputString("chrome://"); });
         // Click near the bottom of the suggestion box to get the last suggestion, which for
-        // "chrome://" should be a valid chrome:// URL. The suggestion that triggers a search can
-        // be in either the middle or top spot depending on whether the
-        // OmniboxGroupSuggestionsBySearchVsUrl feature is enabled or not.
+        // "chrome://" should be a valid chrome:// URL. The suggestion that triggers a search will
+        // be in the top spot because we group by searches vs. URLs.
         NativeUiUtils.clickElement(UserFriendlyElementName.SUGGESTION_BOX, new PointF(0.0f, -0.4f));
         ChromeTabUtils.waitForTabPageLoaded(
                 mTestRule.getActivity().getActivityTab(), (String) null);
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 1aae545..8ad0add6 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -2092,6 +2092,10 @@
             Always open in Adobe Reader
           </message>
         </if>
+        <message name="IDS_DOWNLOAD_MENU_DEEP_SCAN"
+          desc="Download context menu: send file for deep scanning">
+          Scan file
+        </message>
       </if>
 
       <!-- Touch Bar-->
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index c8641a03..33c3e7c6 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2817,12 +2817,6 @@
      flag_descriptions::kOmniboxRichEntitySuggestionsDescription, kOsAll,
      FEATURE_VALUE_TYPE(omnibox::kOmniboxRichEntitySuggestions)},
 
-    {"omnibox-group-suggestions-by-search-vs-url",
-     flag_descriptions::kOmniboxGroupSuggestionsBySearchVsUrlName,
-     flag_descriptions::kOmniboxGroupSuggestionsBySearchVsUrlDescription,
-     kOsAll,
-     FEATURE_VALUE_TYPE(omnibox::kOmniboxGroupSuggestionsBySearchVsUrl)},
-
     {"omnibox-preserve-default-match-against-async-update",
      flag_descriptions::kOmniboxPreserveDefaultMatchAgainstAsyncUpdateName,
      flag_descriptions::
diff --git a/chrome/browser/about_flags_browsertest.cc b/chrome/browser/about_flags_browsertest.cc
index 290987f..8b210413 100644
--- a/chrome/browser/about_flags_browsertest.cc
+++ b/chrome/browser/about_flags_browsertest.cc
@@ -28,6 +28,9 @@
 const char kExpiredFlagName[] = "flag-system-test-flag-2";
 const char kExpiredFlagSwitchName[] = "flag-system-test-expired-switch";
 
+const char kFlagWithOptionSelectorName[] = "flag-system-test-flag-3";
+const char kFlagWithOptionSelectorSwitchName[] = "flag-system-test-switch";
+
 // Command line switch containing an invalid origin.
 const char kUnsanitizedCommandLine[] =
     "http://example-cmdline.test,invalid-cmdline";
@@ -138,7 +141,9 @@
         {{kFlagName, "name-1", "description-1", -1,
           ORIGIN_LIST_VALUE_TYPE(kSwitchName, "")},
          {kExpiredFlagName, "name-2", "description-2", -1,
-          SINGLE_VALUE_TYPE(kExpiredFlagSwitchName)}});
+          SINGLE_VALUE_TYPE(kExpiredFlagSwitchName)},
+         {kFlagWithOptionSelectorName, "name-3", "description-3", -1,
+          SINGLE_VALUE_TYPE(kFlagWithOptionSelectorSwitchName)}});
     flags::testing::SetFlagExpiredPredicate(
         base::BindLambdaForTesting([&](const std::string& name) -> bool {
           return expiration_enabled_ && name == kExpiredFlagName;
@@ -345,4 +350,26 @@
 }
 #endif
 
+IN_PROC_BROWSER_TEST_P(AboutFlagsBrowserTest, FormRestore) {
+  NavigateToFlagsPage();
+  content::WebContents* contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  // Remove the internal_name property from a flag's selector, then synthesize a
+  // change event for it. This simulates what happens during form restoration in
+  // Blink, when navigating back and then forward to the flags page. This test
+  // ensures that that does not crash the browser.
+  // See https://crbug.com/1038638 for more details.
+  EXPECT_TRUE(content::ExecJs(
+      contents,
+      base::StringPrintf(
+          "var k = document.getElementById('%s');"
+          "var s = k.getElementsByClassName('experiment-enable-disable')[0];"
+          "delete s.internal_name;"
+          "const e = document.createEvent('HTMLEvents');"
+          "e.initEvent('change', true, true);"
+          "s.dispatchEvent(e);",
+          kFlagWithOptionSelectorName)));
+}
+
 }  // namespace
diff --git a/chrome/browser/captive_portal/captive_portal_browsertest.cc b/chrome/browser/captive_portal/captive_portal_browsertest.cc
index a487cef..d6b5fef 100644
--- a/chrome/browser/captive_portal/captive_portal_browsertest.cc
+++ b/chrome/browser/captive_portal/captive_portal_browsertest.cc
@@ -71,6 +71,7 @@
 #include "content/public/test/url_loader_interceptor.h"
 #include "net/base/net_errors.h"
 #include "net/cert/x509_certificate.h"
+#include "net/dns/mock_host_resolver.h"
 #include "net/http/transport_security_state.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -910,6 +911,9 @@
       std::make_unique<content::URLLoaderInterceptor>(base::Bind(
           &CaptivePortalBrowserTest::OnIntercept, base::Unretained(this)));
 
+  // Do not introduce DNS errors.
+  host_resolver()->AddRule("*", "127.0.0.1");
+
   // Double-check that the captive portal service isn't enabled by default for
   // browser tests.
   EXPECT_EQ(CaptivePortalService::DISABLED_FOR_TESTING,
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index faca0e9..5504b42 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -4495,6 +4495,7 @@
     mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
         header_client,
     bool* bypass_redirect_checks,
+    bool* disable_secure_dns,
     network::mojom::URLLoaderFactoryOverridePtr* factory_override) {
   bool use_proxy = false;
 
@@ -4520,6 +4521,16 @@
       frame, type == URLLoaderFactoryType::kNavigation, request_initiator,
       factory_receiver);
 
+#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
+  if (disable_secure_dns) {
+    WebContents* web_contents = WebContents::FromRenderFrameHost(frame);
+    *disable_secure_dns =
+        web_contents && CaptivePortalTabHelper::FromWebContents(web_contents) &&
+        CaptivePortalTabHelper::FromWebContents(web_contents)
+            ->is_captive_portal_window();
+  }
+#endif
+
   return use_proxy;
 }
 
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 8554d02..1f7190e 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -470,6 +470,7 @@
       mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
           header_client,
       bool* bypass_redirect_checks,
+      bool* disable_secure_dns,
       network::mojom::URLLoaderFactoryOverridePtr* factory_override) override;
   std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>>
   WillCreateURLLoaderRequestInterceptors(
diff --git a/chrome/browser/chrome_content_browser_client_unittest.cc b/chrome/browser/chrome_content_browser_client_unittest.cc
index 1c7bc9d9..bd025731 100644
--- a/chrome/browser/chrome_content_browser_client_unittest.cc
+++ b/chrome/browser/chrome_content_browser_client_unittest.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/common/webui_url_constants.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/search_engines/template_url_service.h"
@@ -37,6 +38,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/user_agent.h"
 #include "content/public/test/browser_task_environment.h"
+#include "content/public/test/mock_render_process_host.h"
 #include "media/media_buildflags.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -52,6 +54,10 @@
 #include "chrome/test/base/search_test_utils.h"
 #endif
 
+#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
+#include "chrome/browser/captive_portal/captive_portal_tab_helper.h"
+#endif
+
 using content::BrowsingDataFilterBuilder;
 using testing::_;
 using ChromeContentBrowserClientTest = testing::Test;
@@ -488,3 +494,87 @@
   EXPECT_EQ(metadata.architecture, content::BuildCpuInfo());
   EXPECT_EQ(metadata.model, content::BuildModelInfo());
 }
+
+class CaptivePortalCheckProcessHost : public content::MockRenderProcessHost {
+ public:
+  explicit CaptivePortalCheckProcessHost(
+      content::BrowserContext* browser_context)
+      : MockRenderProcessHost(browser_context) {}
+
+  void CreateURLLoaderFactory(
+      mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
+      network::mojom::URLLoaderFactoryParamsPtr params) override {
+    *invoked_url_factory_ = true;
+    DCHECK_EQ(expected_disable_secure_dns_, params->disable_secure_dns);
+  }
+
+  void SetupForTracking(bool* invoked_url_factory,
+                        bool expected_disable_secure_dns) {
+    invoked_url_factory_ = invoked_url_factory;
+    expected_disable_secure_dns_ = expected_disable_secure_dns;
+  }
+
+ private:
+  bool* invoked_url_factory_ = nullptr;
+  bool expected_disable_secure_dns_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(CaptivePortalCheckProcessHost);
+};
+
+class CaptivePortalCheckRenderProcessHostFactory
+    : public content::RenderProcessHostFactory {
+ public:
+  CaptivePortalCheckRenderProcessHostFactory() = default;
+
+  content::RenderProcessHost* CreateRenderProcessHost(
+      content::BrowserContext* browser_context,
+      content::SiteInstance* site_instance) override {
+    rph_ = new CaptivePortalCheckProcessHost(browser_context);
+    return rph_;
+  }
+
+  void SetupForTracking(bool* invoked_url_factory,
+                        bool expected_disable_secure_dns) {
+    rph_->SetupForTracking(invoked_url_factory, expected_disable_secure_dns);
+  }
+
+ private:
+  CaptivePortalCheckProcessHost* rph_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(CaptivePortalCheckRenderProcessHostFactory);
+};
+
+class ChromeContentBrowserClientCaptivePortalBrowserTest
+    : public ChromeRenderViewHostTestHarness {
+ public:
+ protected:
+  void SetUp() override {
+    SetRenderProcessHostFactory(&cp_rph_factory_);
+    ChromeRenderViewHostTestHarness::SetUp();
+  }
+
+  CaptivePortalCheckRenderProcessHostFactory cp_rph_factory_;
+};
+
+TEST_F(ChromeContentBrowserClientCaptivePortalBrowserTest,
+       NotCaptivePortalWindow) {
+  bool invoked_url_factory = false;
+  cp_rph_factory_.SetupForTracking(&invoked_url_factory,
+                                   false /* expected_disable_secure_dns */);
+  NavigateAndCommit(GURL("https://www.google.com"), ui::PAGE_TRANSITION_LINK);
+  EXPECT_TRUE(invoked_url_factory);
+}
+
+#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
+TEST_F(ChromeContentBrowserClientCaptivePortalBrowserTest,
+       CaptivePortalWindow) {
+  bool invoked_url_factory = false;
+  cp_rph_factory_.SetupForTracking(&invoked_url_factory,
+                                   true /* expected_disable_secure_dns */);
+  CaptivePortalTabHelper::CreateForWebContents(web_contents());
+  CaptivePortalTabHelper::FromWebContents(web_contents())
+      ->set_is_captive_portal_window();
+  NavigateAndCommit(GURL("https://www.google.com"), ui::PAGE_TRANSITION_LINK);
+  EXPECT_TRUE(invoked_url_factory);
+}
+#endif
diff --git a/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc b/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
index 70c538b..01992163 100644
--- a/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
+++ b/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
@@ -142,34 +142,43 @@
 const long kLastLaunchTimeWindowStartInJavaTime = 1535760000000;
 const char kDefaultPlatformVersion[] = "1234.0.0";
 
+class TestingDeviceStatusCollectorOptions {
+ public:
+  TestingDeviceStatusCollectorOptions() = default;
+  TestingDeviceStatusCollectorOptions(
+      const TestingDeviceStatusCollectorOptions&) = delete;
+  TestingDeviceStatusCollectorOptions& operator=(
+      const TestingDeviceStatusCollectorOptions&) = delete;
+  ~TestingDeviceStatusCollectorOptions() = default;
+
+  policy::DeviceStatusCollector::VolumeInfoFetcher volume_info_fetcher;
+  policy::DeviceStatusCollector::CPUStatisticsFetcher cpu_fetcher;
+  policy::DeviceStatusCollector::CPUTempFetcher cpu_temp_fetcher;
+  policy::DeviceStatusCollector::AndroidStatusFetcher android_status_fetcher;
+  policy::DeviceStatusCollector::TpmStatusFetcher tpm_status_fetcher;
+  policy::DeviceStatusCollector::EMMCLifetimeFetcher emmc_lifetime_fetcher;
+  policy::DeviceStatusCollector::StatefulPartitionInfoFetcher
+      stateful_partition_info_fetcher;
+  policy::DeviceStatusCollector::CrosHealthdDataFetcher
+      cros_healthd_data_fetcher;
+};
+
 class TestingDeviceStatusCollector : public policy::DeviceStatusCollector {
  public:
   TestingDeviceStatusCollector(
       PrefService* pref_service,
       chromeos::system::StatisticsProvider* provider,
-      const policy::DeviceStatusCollector::VolumeInfoFetcher&
-          volume_info_fetcher,
-      const policy::DeviceStatusCollector::CPUStatisticsFetcher& cpu_fetcher,
-      const policy::DeviceStatusCollector::CPUTempFetcher& cpu_temp_fetcher,
-      const policy::DeviceStatusCollector::AndroidStatusFetcher&
-          android_status_fetcher,
-      const policy::DeviceStatusCollector::TpmStatusFetcher& tpm_status_fetcher,
-      const policy::DeviceStatusCollector::EMMCLifetimeFetcher&
-          emmc_lifetime_fetcher,
-      const policy::DeviceStatusCollector::StatefulPartitionInfoFetcher&
-          stateful_partition_info_fetcher,
-      const policy::DeviceStatusCollector::CrosHealthdDataFetcher&
-          cros_healthd_data_fetcher)
+      std::unique_ptr<TestingDeviceStatusCollectorOptions> options)
       : policy::DeviceStatusCollector(pref_service,
                                       provider,
-                                      volume_info_fetcher,
-                                      cpu_fetcher,
-                                      cpu_temp_fetcher,
-                                      android_status_fetcher,
-                                      tpm_status_fetcher,
-                                      emmc_lifetime_fetcher,
-                                      stateful_partition_info_fetcher,
-                                      cros_healthd_data_fetcher) {
+                                      options->volume_info_fetcher,
+                                      options->cpu_fetcher,
+                                      options->cpu_temp_fetcher,
+                                      options->android_status_fetcher,
+                                      options->tpm_status_fetcher,
+                                      options->emmc_lifetime_fetcher,
+                                      options->stateful_partition_info_fetcher,
+                                      options->cros_healthd_data_fetcher) {
     // Set the baseline time to a fixed value (1 hour after day start) to
     // prevent test flakiness due to a single activity period spanning two days.
     SetBaselineTime(Time::Now().LocalMidnight() + kHour);
@@ -520,35 +529,32 @@
   }
 
   virtual void RestartStatusCollector(
-      const policy::DeviceStatusCollector::VolumeInfoFetcher& volume_info,
-      const policy::DeviceStatusCollector::CPUStatisticsFetcher& cpu_stats,
-      const policy::DeviceStatusCollector::CPUTempFetcher& cpu_temp_fetcher,
-      const policy::DeviceStatusCollector::AndroidStatusFetcher&
-          android_status_fetcher,
-      const policy::DeviceStatusCollector::TpmStatusFetcher& tpm_status_fetcher,
-      const policy::DeviceStatusCollector::EMMCLifetimeFetcher&
-          emmc_lifetime_fetcher,
-      const policy::DeviceStatusCollector::StatefulPartitionInfoFetcher&
-          stateful_partition_info_fetcher,
-      const policy::DeviceStatusCollector::CrosHealthdDataFetcher&
-          cros_healthd_data_fetcher) {
+      std::unique_ptr<TestingDeviceStatusCollectorOptions> options) {
     std::vector<em::VolumeInfo> expected_volume_info;
     status_collector_ = std::make_unique<TestingDeviceStatusCollector>(
-        &local_state_, &fake_statistics_provider_, volume_info, cpu_stats,
-        cpu_temp_fetcher, android_status_fetcher, tpm_status_fetcher,
-        emmc_lifetime_fetcher, stateful_partition_info_fetcher,
-        cros_healthd_data_fetcher);
+        &local_state_, &fake_statistics_provider_, std::move(options));
   }
 
   void RestartStatusCollector() {
-    RestartStatusCollector(base::BindRepeating(&GetEmptyVolumeInfo),
-                           base::BindRepeating(&GetEmptyCPUStatistics),
-                           base::BindRepeating(&GetEmptyCPUTempInfo),
-                           base::BindRepeating(&GetEmptyAndroidStatus),
-                           base::BindRepeating(&GetEmptyTpmStatus),
-                           base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-                           base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-                           base::BindRepeating(&GetEmptyCrosHealthdData));
+    RestartStatusCollector(CreateEmptyDeviceStatusCollectorOptions());
+  }
+
+  std::unique_ptr<TestingDeviceStatusCollectorOptions>
+  CreateEmptyDeviceStatusCollectorOptions() {
+    auto options = std::make_unique<TestingDeviceStatusCollectorOptions>();
+    options->volume_info_fetcher = base::BindRepeating(&GetEmptyVolumeInfo);
+    options->cpu_fetcher = base::BindRepeating(&GetEmptyCPUStatistics);
+    options->cpu_temp_fetcher = base::BindRepeating(&GetEmptyCPUTempInfo);
+    options->android_status_fetcher =
+        base::BindRepeating(&GetEmptyAndroidStatus);
+    options->tpm_status_fetcher = base::BindRepeating(&GetEmptyTpmStatus);
+    options->emmc_lifetime_fetcher =
+        base::BindRepeating(&GetEmptyEMMCLifetimeEstimation);
+    options->stateful_partition_info_fetcher =
+        base::BindRepeating(&GetEmptyStatefulPartitionInfo);
+    options->cros_healthd_data_fetcher =
+        base::BindRepeating(&GetEmptyCrosHealthdData);
+    return options;
   }
 
   void GetStatus() {
@@ -879,14 +885,7 @@
   // Process the list a second time after restarting the collector. It should be
   // able to count the active periods found by the original collector, because
   // the results are stored in a pref.
-  RestartStatusCollector(base::BindRepeating(&GetEmptyVolumeInfo),
-                         base::BindRepeating(&GetEmptyCPUStatistics),
-                         base::BindRepeating(&GetEmptyCPUTempInfo),
-                         base::BindRepeating(&GetEmptyAndroidStatus),
-                         base::BindRepeating(&GetEmptyTpmStatus),
-                         base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-                         base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-                         base::BindRepeating(&GetEmptyCrosHealthdData));
+  RestartStatusCollector(CreateEmptyDeviceStatusCollectorOptions());
   status_collector_->Simulate(test_states,
                               sizeof(test_states) / sizeof(ui::IdleState));
 
@@ -1340,15 +1339,11 @@
   }
   EXPECT_FALSE(expected_volume_info.empty());
 
-  RestartStatusCollector(
-      base::BindRepeating(&GetFakeVolumeInfo, expected_volume_info),
-      base::BindRepeating(&GetEmptyCPUStatistics),
-      base::BindRepeating(&GetEmptyCPUTempInfo),
-      base::BindRepeating(&GetEmptyAndroidStatus),
-      base::BindRepeating(&GetEmptyTpmStatus),
-      base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-      base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-      base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->volume_info_fetcher =
+      base::BindRepeating(&GetFakeVolumeInfo, expected_volume_info);
+  RestartStatusCollector(std::move(options));
+
   // Force finishing tasks posted by ctor of DeviceStatusCollector.
   content::RunAllTasksUntilIdle();
 
@@ -1437,15 +1432,11 @@
 TEST_F(DeviceStatusCollectorTest, TestCPUSamples) {
   // Mock 100% CPU usage.
   std::string full_cpu_usage("cpu  500 0 500 0 0 0 0");
-  RestartStatusCollector(
-      base::BindRepeating(&GetEmptyVolumeInfo),
-      base::BindRepeating(&GetFakeCPUStatistics, full_cpu_usage),
-      base::BindRepeating(&GetEmptyCPUTempInfo),
-      base::BindRepeating(&GetEmptyAndroidStatus),
-      base::BindRepeating(&GetEmptyTpmStatus),
-      base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-      base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-      base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->cpu_fetcher =
+      base::BindRepeating(&GetFakeCPUStatistics, full_cpu_usage);
+  RestartStatusCollector(std::move(options));
+
   // Force finishing tasks posted by ctor of DeviceStatusCollector.
   content::RunAllTasksUntilIdle();
   GetStatus();
@@ -1488,15 +1479,11 @@
   // Mock 100% CPU usage.
   std::string full_cpu_usage("cpu  500 0 500 0 0 0 0");
   int64_t timestamp_lowerbound = base::Time::Now().ToJavaTime();
-  RestartStatusCollector(
-      base::BindRepeating(&GetEmptyVolumeInfo),
-      base::BindRepeating(&GetFakeCPUStatistics, full_cpu_usage),
-      base::BindRepeating(&GetEmptyCPUTempInfo),
-      base::BindRepeating(&GetEmptyAndroidStatus),
-      base::BindRepeating(&GetEmptyTpmStatus),
-      base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-      base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-      base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->cpu_fetcher =
+      base::BindRepeating(&GetFakeCPUStatistics, full_cpu_usage);
+  RestartStatusCollector(std::move(options));
+
   // Force finishing tasks posted by ctor of DeviceStatusCollector.
   content::RunAllTasksUntilIdle();
   int64_t timestamp_upperbound = base::Time::Now().ToJavaTime();
@@ -1568,15 +1555,11 @@
     expected_temp_info.push_back(info);
   }
 
-  RestartStatusCollector(
-      base::BindRepeating(&GetEmptyVolumeInfo),
-      base::BindRepeating(&GetEmptyCPUStatistics),
-      base::BindRepeating(&GetFakeCPUTempInfo, expected_temp_info),
-      base::BindRepeating(&GetEmptyAndroidStatus),
-      base::BindRepeating(&GetEmptyTpmStatus),
-      base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-      base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-      base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->cpu_temp_fetcher =
+      base::BindRepeating(&GetFakeCPUTempInfo, expected_temp_info);
+  RestartStatusCollector(std::move(options));
+
   // Force finishing tasks posted by ctor of DeviceStatusCollector.
   content::RunAllTasksUntilIdle();
 
@@ -1609,15 +1592,11 @@
   em::DiskLifetimeEstimation est;
   est.set_slc(10);
   est.set_mlc(15);
-  RestartStatusCollector(
-      base::BindRepeating(&GetEmptyVolumeInfo),
-      base::BindRepeating(&GetEmptyCPUStatistics),
-      base::BindRepeating(&GetEmptyCPUTempInfo),
-      base::BindRepeating(&GetEmptyAndroidStatus),
-      base::BindRepeating(&GetEmptyTpmStatus),
-      base::BindRepeating(&GetFakeEMMCLifetiemEstimation, est),
-      base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-      base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->emmc_lifetime_fetcher =
+      base::BindRepeating(&GetFakeEMMCLifetiemEstimation, est);
+  RestartStatusCollector(std::move(options));
+
   // Force finishing tasks posted by ctor of DeviceStatusCollector.
   content::RunAllTasksUntilIdle();
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
@@ -1638,15 +1617,10 @@
 }
 
 TEST_F(DeviceStatusCollectorTest, KioskAndroidReporting) {
-  RestartStatusCollector(
-      base::BindRepeating(&GetEmptyVolumeInfo),
-      base::BindRepeating(&GetEmptyCPUStatistics),
-      base::BindRepeating(&GetEmptyCPUTempInfo),
-      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo),
-      base::BindRepeating(&GetEmptyTpmStatus),
-      base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-      base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-      base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->android_status_fetcher =
+      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
+  RestartStatusCollector(std::move(options));
   status_collector_->set_kiosk_account(
       std::make_unique<DeviceLocalAccount>(fake_kiosk_device_local_account_));
   MockRunningKioskApp(fake_kiosk_device_local_account_,
@@ -1663,15 +1637,10 @@
 }
 
 TEST_F(DeviceStatusCollectorTest, NoKioskAndroidReportingWhenDisabled) {
-  RestartStatusCollector(
-      base::BindRepeating(&GetEmptyVolumeInfo),
-      base::BindRepeating(&GetEmptyCPUStatistics),
-      base::BindRepeating(&GetEmptyCPUTempInfo),
-      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo),
-      base::BindRepeating(&GetEmptyTpmStatus),
-      base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-      base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-      base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->android_status_fetcher =
+      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
+  RestartStatusCollector(std::move(options));
 
   // Mock Kiosk app, so some session status is reported
   status_collector_->set_kiosk_account(
@@ -1687,15 +1656,10 @@
 }
 
 TEST_F(DeviceStatusCollectorTest, RegularUserAndroidReporting) {
-  RestartStatusCollector(
-      base::BindRepeating(&GetEmptyVolumeInfo),
-      base::BindRepeating(&GetEmptyCPUStatistics),
-      base::BindRepeating(&GetEmptyCPUTempInfo),
-      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo),
-      base::BindRepeating(&GetEmptyTpmStatus),
-      base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-      base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-      base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->android_status_fetcher =
+      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
+  RestartStatusCollector(std::move(options));
 
   const AccountId account_id(AccountId::FromUserEmail("user0@managed.com"));
   MockRegularUserWithAffiliation(account_id, true);
@@ -1712,15 +1676,10 @@
 }
 
 TEST_F(DeviceStatusCollectorTest, RegularUserCrostiniReporting) {
-  RestartStatusCollector(
-      base::BindRepeating(&GetEmptyVolumeInfo),
-      base::BindRepeating(&GetEmptyCPUStatistics),
-      base::BindRepeating(&GetEmptyCPUTempInfo),
-      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo),
-      base::BindRepeating(&GetEmptyTpmStatus),
-      base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-      base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-      base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->android_status_fetcher =
+      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
+  RestartStatusCollector(std::move(options));
 
   const AccountId account_id(AccountId::FromUserEmail(kCrostiniUserEmail));
   MockRegularUserWithAffiliation(account_id, true);
@@ -1745,15 +1704,10 @@
 }
 
 TEST_F(DeviceStatusCollectorTest, RegularUserCrostiniReportingNoData) {
-  RestartStatusCollector(
-      base::BindRepeating(&GetEmptyVolumeInfo),
-      base::BindRepeating(&GetEmptyCPUStatistics),
-      base::BindRepeating(&GetEmptyCPUTempInfo),
-      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo),
-      base::BindRepeating(&GetEmptyTpmStatus),
-      base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-      base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-      base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->android_status_fetcher =
+      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
+  RestartStatusCollector(std::move(options));
 
   const AccountId account_id(AccountId::FromUserEmail(kCrostiniUserEmail));
   MockRegularUserWithAffiliation(account_id, true);
@@ -1769,15 +1723,10 @@
 }
 
 TEST_F(DeviceStatusCollectorTest, CrostiniTerminaVmKernelVersionReporting) {
-  RestartStatusCollector(
-      base::BindRepeating(&GetEmptyVolumeInfo),
-      base::BindRepeating(&GetEmptyCPUStatistics),
-      base::BindRepeating(&GetEmptyCPUTempInfo),
-      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo),
-      base::BindRepeating(&GetEmptyTpmStatus),
-      base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-      base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-      base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->android_status_fetcher =
+      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
+  RestartStatusCollector(std::move(options));
 
   // Prerequisites for any Crostini reporting to take place:
   const AccountId account_id(AccountId::FromUserEmail(kCrostiniUserEmail));
@@ -1812,15 +1761,10 @@
 }
 
 TEST_F(DeviceStatusCollectorTest, CrostiniAppUsageReporting) {
-  RestartStatusCollector(
-      base::BindRepeating(&GetEmptyVolumeInfo),
-      base::BindRepeating(&GetEmptyCPUStatistics),
-      base::BindRepeating(&GetEmptyCPUTempInfo),
-      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo),
-      base::BindRepeating(&GetEmptyTpmStatus),
-      base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-      base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-      base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->android_status_fetcher =
+      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
+  RestartStatusCollector(std::move(options));
 
   const AccountId account_id(AccountId::FromUserEmail(kCrostiniUserEmail));
   MockRegularUserWithAffiliation(account_id, true);
@@ -1902,15 +1846,10 @@
 
 TEST_F(DeviceStatusCollectorTest,
        TerminalAppIsNotReportedIfCrostiniHasBeenRemoved) {
-  RestartStatusCollector(
-      base::BindRepeating(&GetEmptyVolumeInfo),
-      base::BindRepeating(&GetEmptyCPUStatistics),
-      base::BindRepeating(&GetEmptyCPUTempInfo),
-      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo),
-      base::BindRepeating(&GetEmptyTpmStatus),
-      base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-      base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-      base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->android_status_fetcher =
+      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
+  RestartStatusCollector(std::move(options));
 
   const AccountId account_id(AccountId::FromUserEmail(kCrostiniUserEmail));
   MockRegularUserWithAffiliation(account_id, true);
@@ -1944,15 +1883,10 @@
 }
 
 TEST_F(DeviceStatusCollectorTest, NoRegularUserReportingByDefault) {
-  RestartStatusCollector(
-      base::BindRepeating(&GetEmptyVolumeInfo),
-      base::BindRepeating(&GetEmptyCPUStatistics),
-      base::BindRepeating(&GetEmptyCPUTempInfo),
-      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo),
-      base::BindRepeating(&GetEmptyTpmStatus),
-      base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-      base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-      base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->android_status_fetcher =
+      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
+  RestartStatusCollector(std::move(options));
 
   const AccountId account_id(AccountId::FromUserEmail("user0@managed.com"));
   MockRegularUserWithAffiliation(account_id, true);
@@ -1968,15 +1902,10 @@
 
 TEST_F(DeviceStatusCollectorTest,
        NoRegularUserAndroidReportingWhenNotAffiliated) {
-  RestartStatusCollector(
-      base::BindRepeating(&GetEmptyVolumeInfo),
-      base::BindRepeating(&GetEmptyCPUStatistics),
-      base::BindRepeating(&GetEmptyCPUTempInfo),
-      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo),
-      base::BindRepeating(&GetEmptyTpmStatus),
-      base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-      base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-      base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->android_status_fetcher =
+      base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
+  RestartStatusCollector(std::move(options));
 
   const AccountId account_id(AccountId::FromUserEmail("user0@managed.com"));
   MockRegularUserWithAffiliation(account_id, false);
@@ -2003,14 +1932,10 @@
       0,     /* dictionary_attack_lockout_seconds_remaining */
       true   /* boot_lockbox_finalized */
   };
-  RestartStatusCollector(base::BindRepeating(&GetEmptyVolumeInfo),
-                         base::BindRepeating(&GetEmptyCPUStatistics),
-                         base::BindRepeating(&GetEmptyCPUTempInfo),
-                         base::BindRepeating(&GetEmptyAndroidStatus),
-                         base::BindRepeating(&GetFakeTpmStatus, kFakeTpmStatus),
-                         base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-                         base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-                         base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->tpm_status_fetcher =
+      base::BindRepeating(&GetFakeTpmStatus, kFakeTpmStatus);
+  RestartStatusCollector(std::move(options));
 
   GetStatus();
 
@@ -2407,15 +2332,10 @@
   fakeStatefulPartitionInfo.set_available_space(350);
   fakeStatefulPartitionInfo.set_total_space(500);
 
-  RestartStatusCollector(base::BindRepeating(&GetEmptyVolumeInfo),
-                         base::BindRepeating(&GetEmptyCPUStatistics),
-                         base::BindRepeating(&GetEmptyCPUTempInfo),
-                         base::BindRepeating(&GetEmptyAndroidStatus),
-                         base::BindRepeating(&GetEmptyTpmStatus),
-                         base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-                         base::BindRepeating(&GetFakeStatefulPartitionInfo,
-                                             fakeStatefulPartitionInfo),
-                         base::BindRepeating(&GetEmptyCrosHealthdData));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->stateful_partition_info_fetcher = base::BindRepeating(
+      &GetFakeStatefulPartitionInfo, fakeStatefulPartitionInfo);
+  RestartStatusCollector(std::move(options));
 
   GetStatus();
 
@@ -2499,17 +2419,11 @@
   fake_battery_sample.set_remaining_capacity(kExpectedChargeNow);
   fake_battery_sample.set_temperature(kFakeTemperatureSmart);
 
-  RestartStatusCollector(
-      base::BindRepeating(&GetEmptyVolumeInfo),
-      base::BindRepeating(&GetEmptyCPUStatistics),
-      base::BindRepeating(&GetEmptyCPUTempInfo),
-      base::BindRepeating(&GetEmptyAndroidStatus),
-      base::BindRepeating(&GetEmptyTpmStatus),
-      base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
-      base::BindRepeating(&GetEmptyStatefulPartitionInfo),
-      base::BindRepeating(&GetFakeCrosHealthdData, battery_info,
-                          cached_vpd_info, storage_info, cpu_info,
-                          fake_cpu_temp_sample, fake_battery_sample));
+  auto options = CreateEmptyDeviceStatusCollectorOptions();
+  options->cros_healthd_data_fetcher = base::BindRepeating(
+      &GetFakeCrosHealthdData, battery_info, cached_vpd_info, storage_info,
+      cpu_info, fake_cpu_temp_sample, fake_battery_sample);
+  RestartStatusCollector(std::move(options));
 
   // If kReportDeviceCpuInfo, kReportDevicePowerStatus, and
   // kReportDeviceStorageStatus are false, expect that the data from
diff --git a/chrome/browser/download/download_commands.h b/chrome/browser/download/download_commands.h
index 030b886..e517546 100644
--- a/chrome/browser/download/download_commands.h
+++ b/chrome/browser/download/download_commands.h
@@ -31,8 +31,9 @@
     KEEP,                 // Keep the malicious download.
     LEARN_MORE_SCANNING,  // Show information about download scanning.
     LEARN_MORE_INTERRUPTED,  // Show information about interrupted downloads.
-    COPY_TO_CLIPBOARD,    // Copy the contents to the clipboard.
-    ANNOTATE,             // Open an app to annotate the image.
+    COPY_TO_CLIPBOARD,       // Copy the contents to the clipboard.
+    ANNOTATE,                // Open an app to annotate the image.
+    DEEP_SCAN,               // Send file to Safe Browsing for deep scanning.
   };
 
   // |model| must outlive DownloadCommands.
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc
index 06b66a4..50ef621 100644
--- a/chrome/browser/download/download_item_model.cc
+++ b/chrome/browser/download/download_item_model.cc
@@ -15,6 +15,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/chrome_download_manager_delegate.h"
+#include "chrome/browser/download/download_commands.h"
 #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"
@@ -563,6 +564,7 @@
     case DownloadCommands::KEEP:
     case DownloadCommands::LEARN_MORE_SCANNING:
     case DownloadCommands::LEARN_MORE_INTERRUPTED:
+    case DownloadCommands::DEEP_SCAN:
       return DownloadUIModel::IsCommandEnabled(download_commands, command);
   }
   NOTREACHED();
@@ -596,6 +598,7 @@
     case DownloadCommands::LEARN_MORE_INTERRUPTED:
     case DownloadCommands::COPY_TO_CLIPBOARD:
     case DownloadCommands::ANNOTATE:
+    case DownloadCommands::DEEP_SCAN:
       return false;
   }
   return false;
@@ -690,6 +693,8 @@
     case DownloadCommands::ANNOTATE:
       DownloadUIModel::ExecuteCommand(download_commands, command);
       break;
+    case DownloadCommands::DEEP_SCAN:
+      break;
   }
 }
 #endif
diff --git a/chrome/browser/download/download_shelf_context_menu.cc b/chrome/browser/download/download_shelf_context_menu.cc
index 3a5090b..5d3ecc8 100644
--- a/chrome/browser/download/download_shelf_context_menu.cc
+++ b/chrome/browser/download/download_shelf_context_menu.cc
@@ -5,11 +5,13 @@
 #include "chrome/browser/download/download_shelf_context_menu.h"
 
 #include "build/build_config.h"
+#include "chrome/browser/download/download_commands.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/download/public/common/download_danger_type.h"
 #include "content/public/common/content_features.h"
 #include "extensions/common/extension.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/simple_menu_model.h"
 
 #if defined(OS_WIN)
 #include "chrome/browser/ui/pdf/adobe_reader_info_win.h"
@@ -47,6 +49,9 @@
       download_->GetDangerType() ==
           download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_BLOCK) {
     model = GetInterruptedMenuModel(is_download);
+  } else if (download_->GetDangerType() ==
+             download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING) {
+    model = GetDeepScanningMenuModel(is_download);
   } else if (download_->IsMalicious()) {
     model = GetMaliciousMenuModel(is_download);
   } else if (download_->MightBeMalicious()) {
@@ -164,6 +169,9 @@
       // These commands are implemented only for the Download notification.
       NOTREACHED();
       break;
+    case DownloadCommands::DEEP_SCAN:
+      id = IDS_DOWNLOAD_MENU_DEEP_SCAN;
+      break;
   }
   CHECK(id != -1);
   return l10n_util::GetStringUTF16(id);
@@ -337,3 +345,35 @@
 
   return malicious_download_menu_model_.get();
 }
+
+ui::SimpleMenuModel* DownloadShelfContextMenu::GetDeepScanningMenuModel(
+    bool is_download) {
+  if (deep_scanning_menu_model_)
+    return deep_scanning_menu_model_.get();
+
+  deep_scanning_menu_model_.reset(new ui::SimpleMenuModel(this));
+  deep_scanning_menu_model_->AddItem(
+      DownloadCommands::DEEP_SCAN,
+      GetLabelForCommandId(DownloadCommands::DEEP_SCAN));
+
+  deep_scanning_menu_model_->AddItem(
+      DownloadCommands::DISCARD,
+      GetLabelForCommandId(DownloadCommands::DISCARD));
+
+  deep_scanning_menu_model_->AddItem(
+      DownloadCommands::KEEP, l10n_util::GetStringUTF16(IDS_OPEN_DOWNLOAD_NOW));
+
+  deep_scanning_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
+
+  if (is_download) {
+    deep_scanning_menu_model_->AddItem(
+        DownloadCommands::SHOW_IN_FOLDER,
+        GetLabelForCommandId(DownloadCommands::SHOW_IN_FOLDER));
+    deep_scanning_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
+  }
+
+  deep_scanning_menu_model_->AddItem(
+      DownloadCommands::CANCEL, GetLabelForCommandId(DownloadCommands::CANCEL));
+
+  return deep_scanning_menu_model_.get();
+}
diff --git a/chrome/browser/download/download_shelf_context_menu.h b/chrome/browser/download/download_shelf_context_menu.h
index a7926cfa..01862e7 100644
--- a/chrome/browser/download/download_shelf_context_menu.h
+++ b/chrome/browser/download/download_shelf_context_menu.h
@@ -58,6 +58,7 @@
   ui::SimpleMenuModel* GetInterruptedMenuModel(bool is_download);
   ui::SimpleMenuModel* GetMaybeMaliciousMenuModel(bool is_download);
   ui::SimpleMenuModel* GetMaliciousMenuModel(bool is_download);
+  ui::SimpleMenuModel* GetDeepScanningMenuModel(bool is_download);
 
   // We show slightly different menus if the download is in progress vs. if the
   // download has finished.
@@ -67,6 +68,7 @@
   std::unique_ptr<ui::SimpleMenuModel> interrupted_download_menu_model_;
   std::unique_ptr<ui::SimpleMenuModel> maybe_malicious_download_menu_model_;
   std::unique_ptr<ui::SimpleMenuModel> malicious_download_menu_model_;
+  std::unique_ptr<ui::SimpleMenuModel> deep_scanning_menu_model_;
 
   // Information source.
   DownloadUIModel* download_;
diff --git a/chrome/browser/download/download_ui_model.cc b/chrome/browser/download/download_ui_model.cc
index 8144514e..532caa9 100644
--- a/chrome/browser/download/download_ui_model.cc
+++ b/chrome/browser/download/download_ui_model.cc
@@ -7,6 +7,7 @@
 #include "base/i18n/rtl.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
+#include "chrome/browser/download/download_commands.h"
 #include "chrome/browser/download/offline_item_utils.h"
 #include "chrome/browser/safe_browsing/advanced_protection_status_manager.h"
 #include "chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h"
@@ -308,7 +309,10 @@
       return l10n_util::GetStringFUTF16(
           IDS_PROMPT_DOWNLOAD_SENSITIVE_CONTENT_BLOCKED, elided_filename);
     }
-    case download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING:
+    case download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING: {
+      return l10n_util::GetStringFUTF16(IDS_PROMPT_APP_DEEP_SCANNING,
+                                        elided_filename);
+    }
     case download::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_SAFE:
     case download::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_OPENED_DANGEROUS:
     case download::DOWNLOAD_DANGER_TYPE_ASYNC_SCANNING:
@@ -535,6 +539,7 @@
     case DownloadCommands::KEEP:
     case DownloadCommands::LEARN_MORE_SCANNING:
     case DownloadCommands::LEARN_MORE_INTERRUPTED:
+    case DownloadCommands::DEEP_SCAN:
       return true;
   }
   NOTREACHED();
@@ -561,6 +566,7 @@
     case DownloadCommands::LEARN_MORE_INTERRUPTED:
     case DownloadCommands::COPY_TO_CLIPBOARD:
     case DownloadCommands::ANNOTATE:
+    case DownloadCommands::DEEP_SCAN:
       return false;
   }
   return false;
@@ -610,6 +616,8 @@
       }
 #endif  // defined(OS_CHROMEOS)
       break;
+    case DownloadCommands::DEEP_SCAN:
+      break;
   }
 }
 #endif
diff --git a/chrome/browser/download/notification/download_item_notification.cc b/chrome/browser/download/notification/download_item_notification.cc
index 58de6f0..fe3dc1d 100644
--- a/chrome/browser/download/notification/download_item_notification.cc
+++ b/chrome/browser/download/notification/download_item_notification.cc
@@ -18,6 +18,7 @@
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/note_taking_helper.h"
+#include "chrome/browser/download/download_commands.h"
 #include "chrome/browser/download/download_crx_util.h"
 #include "chrome/browser/download/download_item_model.h"
 #include "chrome/browser/download/notification/download_notification_manager.h"
@@ -175,6 +176,10 @@
       base::RecordAction(
           UserMetricsAction("DownloadNotification.Button_Annotate"));
       break;
+    case DownloadCommands::DEEP_SCAN:
+      base::RecordAction(
+          UserMetricsAction("DownloadNotification.Button_DeepScan"));
+      break;
   }
 }
 
@@ -682,6 +687,7 @@
     case DownloadCommands::ALWAYS_OPEN_TYPE:
     case DownloadCommands::PLATFORM_OPEN:
     case DownloadCommands::LEARN_MORE_INTERRUPTED:
+    case DownloadCommands::DEEP_SCAN:
       // Only for menu.
       NOTREACHED();
       return base::string16();
diff --git a/chrome/browser/download/offline_item_model.cc b/chrome/browser/download/offline_item_model.cc
index 80c837bb..ebc560f 100644
--- a/chrome/browser/download/offline_item_model.cc
+++ b/chrome/browser/download/offline_item_model.cc
@@ -270,6 +270,7 @@
     case DownloadCommands::KEEP:
     case DownloadCommands::LEARN_MORE_SCANNING:
     case DownloadCommands::LEARN_MORE_INTERRUPTED:
+    case DownloadCommands::DEEP_SCAN:
       return DownloadUIModel::IsCommandEnabled(download_commands, command);
   }
   NOTREACHED();
@@ -296,6 +297,7 @@
     case DownloadCommands::LEARN_MORE_INTERRUPTED:
     case DownloadCommands::COPY_TO_CLIPBOARD:
     case DownloadCommands::ANNOTATE:
+    case DownloadCommands::DEEP_SCAN:
       return false;
   }
   return false;
@@ -319,6 +321,7 @@
     case DownloadCommands::RESUME:
     case DownloadCommands::COPY_TO_CLIPBOARD:
     case DownloadCommands::ANNOTATE:
+    case DownloadCommands::DEEP_SCAN:
       DownloadUIModel::ExecuteCommand(download_commands, command);
       break;
   }
diff --git a/chrome/browser/extensions/api/management/management_browsertest.cc b/chrome/browser/extensions/api/management/management_browsertest.cc
index ed3d7a5..b2350057 100644
--- a/chrome/browser/extensions/api/management/management_browsertest.cc
+++ b/chrome/browser/extensions/api/management/management_browsertest.cc
@@ -31,6 +31,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_utils.h"
 #include "content/public/test/url_loader_interceptor.h"
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/extension_host_observer.h"
@@ -459,8 +460,14 @@
   extensions::ExtensionUpdater::CheckParams params2;
   params2.callback = base::BindOnce(&NotificationListener::OnFinished,
                                     base::Unretained(&notification_listener));
-  service->updater()->CheckNow(std::move(params2));
-  ASSERT_TRUE(WaitForExtensionInstallError());
+
+  {
+    content::WindowedNotificationObserver install_error_observer(
+        extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR,
+        content::NotificationService::AllSources());
+    service->updater()->CheckNow(std::move(params2));
+    install_error_observer.Wait();
+  }
   ASSERT_TRUE(notification_listener.started());
   ASSERT_TRUE(notification_listener.finished());
   ASSERT_TRUE(base::Contains(notification_listener.updates(),
diff --git a/chrome/browser/extensions/extension_browsertest.h b/chrome/browser/extensions/extension_browsertest.h
index b9e5b1e6..059bed91 100644
--- a/chrome/browser/extensions/extension_browsertest.h
+++ b/chrome/browser/extensions/extension_browsertest.h
@@ -288,12 +288,6 @@
     return observer_->WaitForPageActionVisibilityChangeTo(count);
   }
 
-  // Wait for an extension install error to be raised. Returns true if an
-  // error was raised.
-  bool WaitForExtensionInstallError() {
-    return observer_->WaitForExtensionInstallError();
-  }
-
   // Wait for the specified extension to crash. Returns true if it really
   // crashed.
   bool WaitForExtensionCrash(const std::string& extension_id) {
diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc
index e5950030..802c25d 100644
--- a/chrome/browser/extensions/extension_prefs_unittest.cc
+++ b/chrome/browser/extensions/extension_prefs_unittest.cc
@@ -27,6 +27,7 @@
 #include "extensions/browser/extension_pref_value_map.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/install_flag.h"
+#include "extensions/browser/pref_names.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/extension_id.h"
@@ -1108,10 +1109,81 @@
 
 TEST_F(ExtensionPrefsObsoletePrefRemoval, ExtensionPrefsObsoletePrefRemoval) {}
 
-using ExtensionPrefsWithholdingTest = testing::Test;
+// Tests the removal of obsolete keys from extension pref entries.
+class ExtensionPrefsIsExternalExtensionUninstalled : public ExtensionPrefsTest {
+ public:
+  ExtensionPrefsIsExternalExtensionUninstalled() = default;
+  ExtensionPrefsIsExternalExtensionUninstalled(
+      const ExtensionPrefsIsExternalExtensionUninstalled& other) = delete;
+  ExtensionPrefsIsExternalExtensionUninstalled& operator=(
+      const ExtensionPrefsIsExternalExtensionUninstalled& other) = delete;
+  ~ExtensionPrefsIsExternalExtensionUninstalled() override = default;
+
+  void Initialize() override {
+    uninstalled_external_id_ =
+        prefs_
+            .AddExtensionWithLocation("external uninstall",
+                                      Manifest::EXTERNAL_PREF)
+            ->id();
+    uninstalled_by_program_external_id_ =
+        prefs_
+            .AddExtensionWithLocation("external uninstall by program",
+                                      Manifest::EXTERNAL_PREF)
+            ->id();
+    installed_external_id_ =
+        prefs_
+            .AddExtensionWithLocation("external install",
+                                      Manifest::EXTERNAL_PREF)
+            ->id();
+    uninstalled_internal_id_ =
+        prefs_
+            .AddExtensionWithLocation("internal uninstall", Manifest::INTERNAL)
+            ->id();
+    installed_internal_id_ =
+        prefs_.AddExtensionWithLocation("internal install", Manifest::INTERNAL)
+            ->id();
+
+    prefs()->OnExtensionUninstalled(uninstalled_external_id_,
+                                    Manifest::EXTERNAL_PREF, false);
+    prefs()->OnExtensionUninstalled(uninstalled_by_program_external_id_,
+                                    Manifest::EXTERNAL_PREF, true);
+    prefs()->OnExtensionUninstalled(uninstalled_internal_id_,
+                                    Manifest::INTERNAL, false);
+  }
+
+  void Verify() override {
+    EXPECT_TRUE(
+        prefs()->IsExternalExtensionUninstalled(uninstalled_external_id_));
+    EXPECT_FALSE(prefs()->IsExternalExtensionUninstalled(
+        uninstalled_by_program_external_id_));
+    EXPECT_FALSE(
+        prefs()->IsExternalExtensionUninstalled(installed_external_id_));
+    EXPECT_FALSE(
+        prefs()->IsExternalExtensionUninstalled(uninstalled_internal_id_));
+    EXPECT_FALSE(
+        prefs()->IsExternalExtensionUninstalled(installed_internal_id_));
+  }
+
+ private:
+  std::string uninstalled_external_id_;
+  std::string uninstalled_by_program_external_id_;
+  std::string installed_external_id_;
+  std::string uninstalled_internal_id_;
+  std::string installed_internal_id_;
+};
+
+TEST_F(ExtensionPrefsIsExternalExtensionUninstalled,
+       ExtensionPrefsIsExternalExtensionUninstalled) {}
+
+////////////////////////////////////////////////////////////////////////////////
+// The following are ExtensionPrefs tests that don't use the same
+// Initialize(), Verify(), <recreate>, Verify() flow that the others do, and
+// instead just use a normal testing::Test setup.
+
+using ExtensionPrefsSimpleTest = testing::Test;
 
 // Tests the migration from the old withholding pref key to the new one.
-TEST_F(ExtensionPrefsWithholdingTest, OldWithholdingPrefMigration) {
+TEST_F(ExtensionPrefsSimpleTest, OldWithholdingPrefMigration) {
   constexpr char kOldPrefKey[] = "extension_can_script_all_urls";
   constexpr char kNewPrefKey[] = "withholding_permissions";
 
@@ -1181,4 +1253,53 @@
                                                 &bool_value));
 }
 
+// TODO(devlin): Remove this when we remove the migration code, circa M84.
+TEST_F(ExtensionPrefsSimpleTest, MigrateToNewExternalUninstallBits) {
+  content::BrowserTaskEnvironment task_environment;
+  TestExtensionPrefs prefs(base::ThreadTaskRunnerHandle::Get());
+
+  auto has_extension_pref_entry = [&prefs](const std::string& id) {
+    const base::DictionaryValue* extensions_dictionary =
+        prefs.pref_service()->GetDictionary(pref_names::kExtensions);
+    if (!extensions_dictionary) {
+      ADD_FAILURE() << "Extensions dictionary is missing!";
+      return false;
+    }
+    return extensions_dictionary->FindDictKey(id) != nullptr;
+  };
+
+  std::string external_extension =
+      prefs
+          .AddExtensionWithLocation("external uninstall",
+                                    Manifest::EXTERNAL_PREF)
+          ->id();
+  std::string internal_extension =
+      prefs.AddExtensionWithLocation("internal", Manifest::INTERNAL)->id();
+
+  EXPECT_TRUE(has_extension_pref_entry(external_extension));
+  EXPECT_TRUE(has_extension_pref_entry(internal_extension));
+  EXPECT_FALSE(
+      prefs.prefs()->IsExternalExtensionUninstalled(external_extension));
+  EXPECT_FALSE(
+      prefs.prefs()->IsExternalExtensionUninstalled(internal_extension));
+
+  // Cheat, and hardcode the old bit for external uninstall state for the
+  // external extension. This is by setting the "state" pref in the extension
+  // dictionary.
+  prefs.prefs()->UpdateExtensionPref(
+      external_extension, "state",
+      std::make_unique<base::Value>(
+          Extension::DEPRECATED_EXTERNAL_EXTENSION_UNINSTALLED));
+
+  // Cause the migration.
+  prefs.RecreateExtensionPrefs();
+
+  EXPECT_FALSE(has_extension_pref_entry(external_extension));
+  EXPECT_TRUE(has_extension_pref_entry(internal_extension));
+  EXPECT_TRUE(
+      prefs.prefs()->IsExternalExtensionUninstalled(external_extension));
+  EXPECT_FALSE(
+      prefs.prefs()->IsExternalExtensionUninstalled(internal_extension));
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 0b8da26..71cbc39 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -1229,7 +1229,7 @@
   ASSERT_TRUE(extension->from_bookmark());
 }
 
-// Test the handling of Extension::EXTERNAL_EXTENSION_UNINSTALLED
+// Test the handling of uninstalling external extensions.
 TEST_F(ExtensionServiceTest, UninstallingExternalExtensions) {
   InitializeEmptyExtensionService();
 
@@ -1293,6 +1293,95 @@
   ASSERT_FALSE(service()->pending_extension_manager()->IsIdPending(good_crx));
 }
 
+// Tests that uninstalling an external extension, and then reinstalling the
+// extension as a user install (e.g. from the webstore) succeeds.
+TEST_F(ExtensionServiceTest, UninstallExternalExtensionAndReinstallAsUser) {
+  InitializeEmptyExtensionService();
+
+  base::FilePath path = data_dir().AppendASCII("good.crx");
+
+  std::string version_str = "1.0.0.0";
+  // Install an external extension.
+  std::unique_ptr<ExternalInstallInfoFile> info =
+      CreateExternalExtension(good_crx, version_str, path,
+                              Manifest::EXTERNAL_PREF, Extension::NO_FLAGS);
+  MockExternalProvider* provider =
+      AddMockExternalProvider(Manifest::EXTERNAL_PREF);
+  provider->UpdateOrAddExtension(std::move(info));
+  WaitForExternalExtensionInstalled();
+
+  ASSERT_TRUE(registry()->enabled_extensions().GetByID(good_crx));
+
+  // Uninstall the extension.
+  UninstallExtension(good_crx);
+  ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
+  EXPECT_TRUE(prefs->IsExternalExtensionUninstalled(good_crx));
+
+  // Reinstall the extension as a user-space extension. This should succeed.
+  scoped_refptr<CrxInstaller> installer(CrxInstaller::CreateSilent(service()));
+  installer->set_allow_silent_install(true);
+  base::RunLoop run_loop;
+  installer->set_installer_callback(base::Bind(
+      [](base::Closure quit_closure,
+         const base::Optional<CrxInstallError>& result) {
+        ASSERT_FALSE(result) << result->message();
+        quit_closure.Run();
+      },
+      run_loop.QuitWhenIdleClosure()));
+  installer->InstallCrx(path);
+  run_loop.Run();
+
+  ASSERT_TRUE(registry()->enabled_extensions().GetByID(good_crx));
+}
+
+// Tests uninstalling an external extension from a higher version, and then
+// installing a lower version as a user. This should succeed.
+// Regression test for https://crbug.com/795026.
+TEST_F(ExtensionServiceTest,
+       UninstallExternalExtensionAndReinstallAsUserWithLowerVersion) {
+  InitializeEmptyExtensionService();
+
+  base::FilePath path = data_dir().AppendASCII("good2.crx");
+
+  constexpr char kExternalVersion[] = "1.0.0.1";
+  // Install an external extension.
+  std::unique_ptr<ExternalInstallInfoFile> info =
+      CreateExternalExtension(good_crx, kExternalVersion, path,
+                              Manifest::EXTERNAL_PREF, Extension::NO_FLAGS);
+  MockExternalProvider* provider =
+      AddMockExternalProvider(Manifest::EXTERNAL_PREF);
+  provider->UpdateOrAddExtension(std::move(info));
+  WaitForExternalExtensionInstalled();
+
+  ASSERT_TRUE(registry()->enabled_extensions().GetByID(good_crx));
+
+  // Uninstall the extension.
+  UninstallExtension(good_crx);
+  ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
+  EXPECT_TRUE(prefs->IsExternalExtensionUninstalled(good_crx));
+
+  // Reinstall the extension as a user-space extension with a lower version.
+  // This should succeed.
+  scoped_refptr<CrxInstaller> installer(CrxInstaller::CreateSilent(service()));
+  installer->set_allow_silent_install(true);
+  base::RunLoop run_loop;
+  installer->set_installer_callback(base::Bind(
+      [](base::Closure quit_closure,
+         const base::Optional<CrxInstallError>& result) {
+        ASSERT_FALSE(result) << result->message();
+        quit_closure.Run();
+      },
+      run_loop.QuitWhenIdleClosure()));
+  installer->InstallCrx(data_dir().AppendASCII("good.crx"));
+  run_loop.Run();
+
+  const Extension* extension =
+      registry()->enabled_extensions().GetByID(good_crx);
+  ASSERT_TRUE(extension);
+  constexpr char kLowerVersion[] = "1.0.0.0";
+  EXPECT_EQ(kLowerVersion, extension->version().GetString());
+}
+
 // Test that uninstalling an external extension does not crash when
 // the extension could not be loaded.
 // This extension shown in preferences file requires an experimental permission.
diff --git a/chrome/browser/extensions/installed_loader.cc b/chrome/browser/extensions/installed_loader.cc
index e16dd1fe..019deac 100644
--- a/chrome/browser/extensions/installed_loader.cc
+++ b/chrome/browser/extensions/installed_loader.cc
@@ -617,25 +617,6 @@
     }
   }
 
-  std::unique_ptr<ExtensionPrefs::ExtensionsInfo> uninstalled_extensions_info(
-      extension_prefs_->GetUninstalledExtensionsInfo());
-  for (size_t i = 0; i < uninstalled_extensions_info->size(); ++i) {
-    ExtensionInfo* info = uninstalled_extensions_info->at(i).get();
-    if (Manifest::IsExternalLocation(info->extension_location)) {
-      std::string update_url;
-      if (info->extension_manifest->GetString("update_url", &update_url) &&
-          extension_urls::IsWebstoreUpdateUrl(GURL(update_url))) {
-        UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
-                                  EXTERNAL_ITEM_WEBSTORE_UNINSTALLED,
-                                  EXTERNAL_ITEM_MAX_ITEMS);
-      } else {
-        UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
-                                  EXTERNAL_ITEM_NONWEBSTORE_UNINSTALLED,
-                                  EXTERNAL_ITEM_MAX_ITEMS);
-      }
-    }
-  }
-
   base::UmaHistogramCounts100("Extensions.LoadApp",
                               app_user_count + app_external_count);
   base::UmaHistogramCounts100("Extensions.LoadAppUser", app_user_count);
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index d1577afa2..d891360 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2791,11 +2791,6 @@
     "expiry_milestone": 85
   },
   {
-    "name": "omnibox-group-suggestions-by-search-vs-url",
-    "owners": [ "krb", "chrome-omnibox-team@google.com" ],
-    "expiry_milestone": 82
-  },
-  {
     "name": "omnibox-local-entity-suggestions",
     "owners": [ "manukh", "chrome-omnibox-team@google.com" ],
     "expiry_milestone": 85
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 009efcb..3a8a7b82 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1405,12 +1405,6 @@
     "Enables an experimental scoring mode for suggestions when Google is the "
     "default search engine.";
 
-const char kOmniboxGroupSuggestionsBySearchVsUrlName[] =
-    "Omnibox Group Suggestions By Search vs URL";
-const char kOmniboxGroupSuggestionsBySearchVsUrlDescription[] =
-    "Group suggestions by major type, search then navigation, except for "
-    "the default match which must be first.";
-
 const char kOmniboxLocalEntitySuggestionsName[] =
     "Omnibox Local Entity Suggestions";
 const char kOmniboxLocalEntitySuggestionsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index a78fae2..b2bafef 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -850,9 +850,6 @@
 extern const char kOmniboxExperimentalSuggestScoringName[];
 extern const char kOmniboxExperimentalSuggestScoringDescription[];
 
-extern const char kOmniboxGroupSuggestionsBySearchVsUrlName[];
-extern const char kOmniboxGroupSuggestionsBySearchVsUrlDescription[];
-
 extern const char kOmniboxLocalEntitySuggestionsName[];
 extern const char kOmniboxLocalEntitySuggestionsDescription[];
 
diff --git a/chrome/browser/net/errorpage_browsertest.cc b/chrome/browser/net/errorpage_browsertest.cc
index e835004..d8ebcb6 100644
--- a/chrome/browser/net/errorpage_browsertest.cc
+++ b/chrome/browser/net/errorpage_browsertest.cc
@@ -1421,10 +1421,27 @@
 
   // InProcessBrowserTest:
   void SetUpOnMainThread() override {
+    // ERR_UNSAFE_PORT will not trigger navigation corrections.
+    url_loader_interceptor_ =
+        std::make_unique<content::URLLoaderInterceptor>(base::BindRepeating(
+            [](content::URLLoaderInterceptor::RequestParams* params) {
+              if (params->url_request.url.host() == kHostname) {
+                params->client->OnComplete(
+                    network::URLLoaderCompletionStatus(net::ERR_UNSAFE_PORT));
+                return true;
+              }
+              return false;
+            }));
+
     // Clear AcceptLanguages to force punycode decoding.
     browser()->profile()->GetPrefs()->SetString(
         language::prefs::kAcceptLanguages, std::string());
   }
+
+  void TearDownOnMainThread() override { url_loader_interceptor_.reset(); }
+
+ private:
+  std::unique_ptr<content::URLLoaderInterceptor> url_loader_interceptor_;
 };
 
 const char ErrorPageForIDNTest::kHostname[] =
@@ -1435,11 +1452,8 @@
 
 // Make sure error page shows correct unicode for IDN.
 IN_PROC_BROWSER_TEST_F(ErrorPageForIDNTest, IDN) {
-  // ERR_UNSAFE_PORT will not trigger navigation corrections.
-  ui_test_utils::NavigateToURL(
-      browser(),
-      URLRequestFailedJob::GetMockHttpUrlForHostname(net::ERR_UNSAFE_PORT,
-                                                     kHostname));
+  ui_test_utils::NavigateToURL(browser(),
+                               GURL("http://" + std::string(kHostname) + "/"));
   EXPECT_TRUE(IsDisplayingText(browser(), kHostnameJSUnicode));
 }
 
diff --git a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.cc
index 12d874a4..1c92874 100644
--- a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.cc
@@ -150,8 +150,11 @@
   // Filter out first-party frames.
   content::RenderFrameHost* top_frame =
       GetDelegate().GetWebContents()->GetMainFrame();
-  if (!top_frame || top_frame->GetLastCommittedOrigin().IsSameOriginWith(
-                        subframe_rfh->GetLastCommittedOrigin())) {
+  if (!top_frame ||
+      net::registry_controlled_domains::SameDomainOrHost(
+          top_frame->GetLastCommittedOrigin(),
+          subframe_rfh->GetLastCommittedOrigin(),
+          net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) {
     return;
   }
 
diff --git a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_unittest.cc
index 00a8c34d..0b5d18b 100644
--- a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_unittest.cc
@@ -71,7 +71,7 @@
 TEST_F(ThirdPartyMetricsObserverTest, NoThirdPartyFrame_NoneRecorded) {
   RenderFrameHost* main_frame = NavigateMainFrame("https://top.com");
   RenderFrameHost* sub_frame =
-      CreateAndNavigateSubFrame("https://top.com/foo", main_frame);
+      CreateAndNavigateSubFrame("https://a.top.com/foo", main_frame);
 
   page_load_metrics::mojom::PageLoadTiming timing;
   page_load_metrics::InitPageLoadTimingForTest(&timing);
diff --git a/chrome/browser/performance_manager/observers/isolation_context_metrics.cc b/chrome/browser/performance_manager/observers/isolation_context_metrics.cc
index a0aefd96..d9c1852 100644
--- a/chrome/browser/performance_manager/observers/isolation_context_metrics.cc
+++ b/chrome/browser/performance_manager/observers/isolation_context_metrics.cc
@@ -79,16 +79,6 @@
     "PerformanceManager.FrameSiteInstanceProcessRelationship.ByProcess2";
 
 // static
-const char
-    IsolationContextMetrics::kBrowsingInstanceDataByPageTimeHistogramName[] =
-        "PerformanceManager.BrowsingInstancePluralityVisibilityState."
-        "ByPageTime";
-
-// static
-const char IsolationContextMetrics::kBrowsingInstanceDataByTimeHistogramName[] =
-    "PerformanceManager.BrowsingInstancePluralityVisibilityState.ByTime";
-
-// static
 const char IsolationContextMetrics::kFramesPerRendererByTimeHistogram[] =
     "PerformanceManager.FramesPerRendererByTime";
 
@@ -122,25 +112,6 @@
     const FrameNode* frame_node) {
   // Track frame node deaths and use that to keep ProcessData up to date.
   ChangeFrameCount(frame_node, -1);
-
-  // If the frame is the current main frame of a page, then remove the page
-  // from the browsing instance as well.
-  if (frame_node->IsMainFrame() && frame_node->IsCurrent()) {
-    ChangePageCount(frame_node->GetPageNode(),
-                    frame_node->GetBrowsingInstanceId(), -1);
-  }
-}
-
-void IsolationContextMetrics::OnIsCurrentChanged(const FrameNode* frame_node) {
-  if (!frame_node->IsMainFrame())
-    return;
-
-  const auto* page_node = frame_node->GetPageNode();
-  DCHECK(page_node);
-  const int32_t browsing_instance_id = frame_node->GetBrowsingInstanceId();
-
-  const int delta = frame_node->IsCurrent() ? 1 : -1;
-  ChangePageCount(page_node, browsing_instance_id, delta);
 }
 
 void IsolationContextMetrics::OnPassedToGraph(Graph* graph) {
@@ -153,46 +124,6 @@
   graph_ = nullptr;
 }
 
-void IsolationContextMetrics::OnIsVisibleChanged(const PageNode* page_node) {
-  // If there is no current main frame node associated with the page, we will
-  // capture the visibility event when a node is added and made current via
-  // "OnIsCurrentChanged".
-  const auto* frame_node = page_node->GetMainFrameNode();
-  if (!frame_node || !frame_node->IsCurrent())
-    return;
-
-  // Get the data related to this browsing instance. Since there is a current
-  // main frame it must already have existed.
-  DCHECK(base::Contains(browsing_instance_data_,
-                        frame_node->GetBrowsingInstanceId()));
-  auto* data = &browsing_instance_data_[frame_node->GetBrowsingInstanceId()];
-  const BrowsingInstanceDataState old_state =
-      GetBrowsingInstanceDataState(data);
-  const int old_page_count = data->page_count;
-  DCHECK_NE(BrowsingInstanceDataState::kUndefined, old_state);
-  DCHECK_LT(0, data->page_count);
-
-  if (page_node->IsVisible()) {
-    ++data->visible_page_count;
-    DCHECK_LE(data->visible_page_count, data->page_count);
-  } else {
-    DCHECK_LT(0, data->visible_page_count);
-    --data->visible_page_count;
-  }
-
-  // Report the data if the state has changed.
-  const BrowsingInstanceDataState new_state =
-      GetBrowsingInstanceDataState(data);
-  if (old_state != new_state) {
-    // Report the state change. Flush all other related data so as not to
-    // introduce bias into the metrics when only a partial reporting cycle
-    // occurs.
-    const auto now = base::TimeTicks::Now();
-    ReportBrowsingInstanceData(data, old_page_count, old_state, now);
-    ReportAllBrowsingInstanceData(now);
-  }
-}
-
 void IsolationContextMetrics::OnBeforeProcessNodeRemoved(
     const ProcessNode* process_node) {
   // Track process death and use that to report whether or not the process
@@ -211,14 +142,12 @@
 
 void IsolationContextMetrics::RegisterObservers(Graph* graph) {
   graph->AddFrameNodeObserver(this);
-  graph->AddPageNodeObserver(this);
   graph->AddProcessNodeObserver(this);
   StartTimer();
 }
 
 void IsolationContextMetrics::UnregisterObservers(Graph* graph) {
   graph->RemoveFrameNodeObserver(this);
-  graph->RemovePageNodeObserver(this);
   graph->RemoveProcessNodeObserver(this);
 
   // Drain all metrics on shutdown to avoid losing the tail.
@@ -320,99 +249,9 @@
   ReportAllProcessData(now);
 }
 
-// static
-IsolationContextMetrics::BrowsingInstanceDataState
-IsolationContextMetrics::GetBrowsingInstanceDataState(
-    const BrowsingInstanceData* browsing_instance_data) {
-  if (browsing_instance_data->page_count == 0)
-    return BrowsingInstanceDataState::kUndefined;
-
-  if (browsing_instance_data->page_count == 1) {
-    if (browsing_instance_data->visible_page_count == 1)
-      return BrowsingInstanceDataState::kSinglePageForeground;
-    return BrowsingInstanceDataState::kSinglePageBackground;
-  }
-
-  if (browsing_instance_data->visible_page_count > 0)
-    return BrowsingInstanceDataState::kMultiPageSomeForeground;
-  return BrowsingInstanceDataState::kMultiPageBackground;
-}
-
-// static
-void IsolationContextMetrics::ReportBrowsingInstanceData(
-    BrowsingInstanceData* browsing_instance_data,
-    int page_count,
-    BrowsingInstanceDataState state,
-    base::TimeTicks now) {
-  const int seconds = GetSecondsSinceLastReportAndUpdate(
-      now, kReportingInterval, browsing_instance_data);
-  if (seconds) {
-    DCHECK_LT(0, page_count);
-    AddCountsToHistogram<kBrowsingInstanceDataByPageTimeHistogramName>(
-        state, seconds * page_count);
-    AddCountsToHistogram<kBrowsingInstanceDataByTimeHistogramName>(state,
-                                                                   seconds);
-  }
-}
-
-void IsolationContextMetrics::ReportAllBrowsingInstanceData(
-    base::TimeTicks now) {
-  for (auto& id_data_pair : browsing_instance_data_) {
-    auto* data = &id_data_pair.second;
-    ReportBrowsingInstanceData(data, data->page_count,
-                               GetBrowsingInstanceDataState(data), now);
-  }
-}
-
-void IsolationContextMetrics::ChangePageCount(const PageNode* page_node,
-                                              int32_t browsing_instance_id,
-                                              int delta) {
-  DCHECK(delta == -1 || delta == 1);
-
-  auto iter =
-      browsing_instance_data_
-          .insert(std::make_pair(browsing_instance_id, BrowsingInstanceData()))
-          .first;
-  auto* data = &iter->second;
-
-  BrowsingInstanceDataState old_state = GetBrowsingInstanceDataState(data);
-  int old_page_count = data->page_count;
-
-  // Modify the page counts, checking invariants before and after.
-  DCHECK_LE(0, data->page_count);
-  DCHECK_LE(0, data->visible_page_count);
-  DCHECK_LE(data->visible_page_count, data->page_count);
-  data->page_count += delta;
-  if (page_node->IsVisible())
-    data->visible_page_count += delta;
-  DCHECK_LE(0, data->page_count);
-  DCHECK_LE(0, data->visible_page_count);
-  DCHECK_LE(data->visible_page_count, data->page_count);
-
-  BrowsingInstanceDataState new_state = GetBrowsingInstanceDataState(data);
-
-  // No point reporting anything if this is newly created, or if the state
-  // hasn't changed.
-  if (old_state != BrowsingInstanceDataState::kUndefined &&
-      old_state != new_state) {
-    // Report the state change. Flush all other related data so as not to
-    // introduce bias into the metrics when only a partial reporting cycle
-    // occurs.
-    const auto now = base::TimeTicks::Now();
-    ReportBrowsingInstanceData(data, old_page_count, old_state, now);
-    ReportAllBrowsingInstanceData(now);
-  }
-
-  // If the page count is down to zero then the browsing instance can be
-  // erased. Note that |data| becomes an invalid pointer after this point.
-  if (data->page_count == 0)
-    browsing_instance_data_.erase(iter);
-}
-
 void IsolationContextMetrics::OnReportingTimerFired() {
   const auto now = base::TimeTicks::Now();
   ReportAllProcessData(now);
-  ReportAllBrowsingInstanceData(now);
 }
 
 IsolationContextMetrics::ProcessData::ProcessData()
@@ -437,10 +276,4 @@
               ->process_data;
 }
 
-IsolationContextMetrics::BrowsingInstanceData::BrowsingInstanceData()
-    : last_reported(base::TimeTicks::Now()) {}
-
-IsolationContextMetrics::BrowsingInstanceData::~BrowsingInstanceData() =
-    default;
-
 }  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/observers/isolation_context_metrics.h b/chrome/browser/performance_manager/observers/isolation_context_metrics.h
index c0aaeac1..f272d0c 100644
--- a/chrome/browser/performance_manager/observers/isolation_context_metrics.h
+++ b/chrome/browser/performance_manager/observers/isolation_context_metrics.h
@@ -12,7 +12,6 @@
 #include "base/timer/timer.h"
 #include "components/performance_manager/public/graph/frame_node.h"
 #include "components/performance_manager/public/graph/graph.h"
-#include "components/performance_manager/public/graph/page_node.h"
 #include "components/performance_manager/public/graph/process_node.h"
 
 namespace performance_manager {
@@ -29,7 +28,6 @@
 //     the impact of extending freezing logic to entire browsing instances.
 class IsolationContextMetrics : public FrameNode::ObserverDefaultImpl,
                                 public GraphOwned,
-                                public PageNode::ObserverDefaultImpl,
                                 public ProcessNode::ObserverDefaultImpl {
  public:
   IsolationContextMetrics();
@@ -57,16 +55,6 @@
   // from distinct site instances, versus those that ever host more than one
   // frame from the same site instance. See ProcessDataState for details.
   static const char kProcessDataByProcessHistogramName[];
-  // This histogram tallies the cumulative amount of time pages spent in the
-  // foreground versus background, and as sole occupants of a browsing instance
-  // versus in a shared browsing instance. See BrowsingInstanceDataState for
-  // more details.
-  static const char kBrowsingInstanceDataByPageTimeHistogramName[];
-  // This histogram tallies the cumulative amount of time browsing instances
-  // spend in the foreground versus background, and as browsing instances with
-  // only one page versus multi-page browsing instances. See
-  // BrowsingInstanceDataState for more details.
-  static const char kBrowsingInstanceDataByTimeHistogramName[];
   // This histogram records the number of frames in a renderer over time.
   static const char kFramesPerRendererByTimeHistogram[];
   // This histogram records the number of site instances in a renderer over
@@ -114,45 +102,14 @@
     kMaxValue = kOnlyOneFrameExists
   };
 
-  // Tracks summary information regarding pages in a browsing instance.
-  struct BrowsingInstanceData {
-    BrowsingInstanceData();
-    ~BrowsingInstanceData();
-
-    // The number of pages in this browsing instance.
-    int page_count = 0;
-    // The number of visible pages in this browsing instance. This is always
-    // <= |page_count|.
-    int visible_page_count = 0;
-    // The last time the data related to this browsing instance was reported to
-    // the histogram. This happens on a timer or on state changes. This is
-    // initialized to the time of the struct creation.
-    base::TimeTicks last_reported;
-  };
-
-  // A state that can be calculated from a BrowsingInstanceData. The
-  // non-negative values are used in a histogram, so should not be modified.
-  enum class BrowsingInstanceDataState {
-    kUndefined = -1,  // This value is never reported, but used in logic.
-    kSinglePageForeground = 0,
-    kSinglePageBackground = 1,
-    kMultiPageSomeForeground = 2,     // At least one page is foreground.
-    kMultiPageBackground = 3,         // All pages are background.
-    kMaxValue = kMultiPageBackground  // Must be maintained as the max value.
-  };
-
   // FrameNodeObserver implementation:
   void OnFrameNodeAdded(const FrameNode* frame_node) override;
   void OnBeforeFrameNodeRemoved(const FrameNode* frame_node) override;
-  void OnIsCurrentChanged(const FrameNode* frame_node) override;
 
   // GraphOwned implementation:
   void OnPassedToGraph(Graph* graph) override;
   void OnTakenFromGraph(Graph* graph) override;
 
-  // PageNodeObserver implementation:
-  void OnIsVisibleChanged(const PageNode* page_node) override;
-
   // ProcessNodeObserver implementation:
   void OnBeforeProcessNodeRemoved(const ProcessNode* process_node) override;
 
@@ -177,30 +134,6 @@
   // be +/- 1.
   void ChangeFrameCount(const FrameNode* frame_node, int delta);
 
-  // Returns the state associated with a BrowsingInstanceData.
-  static BrowsingInstanceDataState GetBrowsingInstanceDataState(
-      const BrowsingInstanceData* browsing_instance_data);
-
-  // Reports the data associated with a browsing instance.
-  static void ReportBrowsingInstanceData(
-      BrowsingInstanceData* browsing_instance_data,
-      int page_count,
-      BrowsingInstanceDataState state,
-      base::TimeTicks now);
-
-  // Reports all current browsing instance data.
-  void ReportAllBrowsingInstanceData(base::TimeTicks now);
-
-  // Updates |browsing_instance_data_| as pages are added and removed from
-  // a browsing instance. The |delta| must be +/- 1.
-  void ChangePageCount(const PageNode* page_node,
-                       int32_t browsing_instance_id,
-                       int delta);
-  void OnPageAddedToBrowsingInstance(const PageNode* page_node,
-                                     int32_t browsing_instance_id);
-  void OnPageRemovedFromBrowsingInstance(const PageNode* page_node,
-                                         int32_t browsing_instance_id);
-
   // This is virtual in order to provide a testing seam.
   virtual void OnReportingTimerFired();
 
@@ -216,11 +149,6 @@
   // https://crbug.com/961468
   base::RepeatingTimer reporting_timer_;
 
-  // Tracks data related to all currently known browsing instances. 90% of users
-  // don't have more than 10 tabs open according to Tabs.MaxTabsInADay.
-  base::small_map<std::unordered_map<int32_t, BrowsingInstanceData>, 10>
-      browsing_instance_data_;
-
  private:
   DISALLOW_COPY_AND_ASSIGN(IsolationContextMetrics);
 };
diff --git a/chrome/browser/performance_manager/observers/isolation_context_metrics_unittest.cc b/chrome/browser/performance_manager/observers/isolation_context_metrics_unittest.cc
index 087c1a2..482e09e 100644
--- a/chrome/browser/performance_manager/observers/isolation_context_metrics_unittest.cc
+++ b/chrome/browser/performance_manager/observers/isolation_context_metrics_unittest.cc
@@ -25,13 +25,7 @@
   }
 
   // Expose some things for testing.
-  using IsolationContextMetrics::browsing_instance_data_;
-  using IsolationContextMetrics::BrowsingInstanceData;
-  using IsolationContextMetrics::BrowsingInstanceDataState;
-  using IsolationContextMetrics::GetBrowsingInstanceDataState;
   using IsolationContextMetrics::GetProcessDataState;
-  using IsolationContextMetrics::kBrowsingInstanceDataByPageTimeHistogramName;
-  using IsolationContextMetrics::kBrowsingInstanceDataByTimeHistogramName;
   using IsolationContextMetrics::kFramesPerRendererByTimeHistogram;
   using IsolationContextMetrics::kProcessDataByProcessHistogramName;
   using IsolationContextMetrics::kProcessDataByTimeHistogramName;
@@ -57,10 +51,6 @@
   // Bring some types into the namespace for convenience.
   using ProcessData = TestIsolationContextMetrics::ProcessData;
   using ProcessDataState = TestIsolationContextMetrics::ProcessDataState;
-  using BrowsingInstanceData =
-      TestIsolationContextMetrics::BrowsingInstanceData;
-  using BrowsingInstanceDataState =
-      TestIsolationContextMetrics::BrowsingInstanceDataState;
 
   // Browsing instance IDs.
   static constexpr int32_t kBID1 = 1;
@@ -80,21 +70,6 @@
     graph()->PassToGraph(base::WrapUnique(metrics_));
   }
 
-  void ExpectBrowsingInstanceData(int32_t browsing_instance_id,
-                                  int page_count,
-                                  int visible_page_count) {
-    auto iter = metrics_->browsing_instance_data_.find(browsing_instance_id);
-    EXPECT_TRUE(iter != metrics_->browsing_instance_data_.end());
-    auto& data = iter->second;
-    EXPECT_EQ(page_count, data.page_count);
-    EXPECT_EQ(visible_page_count, data.visible_page_count);
-  }
-
-  void ExpectNoBrowsingInstanceData(int32_t browsing_instance_id) {
-    auto iter = metrics_->browsing_instance_data_.find(browsing_instance_id);
-    EXPECT_TRUE(iter == metrics_->browsing_instance_data_.end());
-  }
-
   // A frame node constructor that lets us specify the browsing instance ID and
   // site instance ID, but defaults everything else.
   TestNodeWrapper<FrameNodeImpl> CreateFrameNode(
@@ -406,191 +381,4 @@
   }
 }
 
-TEST_F(IsolationContextMetricsTest, GetBrowsingInstanceDataState) {
-  TestIsolationContextMetrics::BrowsingInstanceData data;
-  EXPECT_EQ(0, data.page_count);
-  EXPECT_EQ(0, data.visible_page_count);
-  EXPECT_EQ(task_env().NowTicks(), data.last_reported);
-  EXPECT_EQ(BrowsingInstanceDataState::kUndefined,
-            TestIsolationContextMetrics::GetBrowsingInstanceDataState(&data));
-
-  // Add a page.
-  data.page_count = 1;
-  EXPECT_EQ(BrowsingInstanceDataState::kSinglePageBackground,
-            TestIsolationContextMetrics::GetBrowsingInstanceDataState(&data));
-
-  // Make it foreground.
-  data.visible_page_count = 1;
-  EXPECT_EQ(BrowsingInstanceDataState::kSinglePageForeground,
-            TestIsolationContextMetrics::GetBrowsingInstanceDataState(&data));
-
-  // Add another background page.
-  data.page_count = 2;
-  EXPECT_EQ(BrowsingInstanceDataState::kMultiPageSomeForeground,
-            TestIsolationContextMetrics::GetBrowsingInstanceDataState(&data));
-
-  // Add another background page.
-  data.page_count = 3;
-  EXPECT_EQ(BrowsingInstanceDataState::kMultiPageSomeForeground,
-            TestIsolationContextMetrics::GetBrowsingInstanceDataState(&data));
-
-  // Make all the pages background.
-  data.visible_page_count = 0;
-  EXPECT_EQ(BrowsingInstanceDataState::kMultiPageBackground,
-            TestIsolationContextMetrics::GetBrowsingInstanceDataState(&data));
-}
-
-TEST_F(IsolationContextMetricsTest, BrowsingInstanceDataReporting) {
-  metrics_->StartTimer();
-
-  // Create a process that hosts 1 frame from 1 page.
-  auto process = CreateNode<ProcessNodeImpl>();
-  auto page1 = CreateNode<PageNodeImpl>();
-  auto frame1 = CreateFrameNode(process.get(), page1.get(), kBID1, kSID1);
-  frame1->SetIsCurrent(true);
-  ExpectBrowsingInstanceData(kBID1, 1, 0);
-
-  // Advance time and add another page with 1 frame in a different browsing
-  // instance, but in the same process.
-  AdvanceClock(base::TimeDelta::FromSeconds(1));
-  auto page2 = CreateNode<PageNodeImpl>();
-  auto frame2 = CreateFrameNode(process.get(), page2.get(), kBID2, kSID2);
-  frame2->SetIsCurrent(true);
-  ExpectBrowsingInstanceData(kBID1, 1, 0);
-  ExpectBrowsingInstanceData(kBID2, 1, 0);
-  // Expect no samples, as the state didn't change; it's yet another
-  // background page in yet another browsing instance.
-  histogram_tester_.ExpectTotalCount(
-      metrics_->kBrowsingInstanceDataByTimeHistogramName, 0);
-  histogram_tester_.ExpectTotalCount(
-      metrics_->kBrowsingInstanceDataByPageTimeHistogramName, 0);
-
-  // Make the first page visible. This should drive a state change. Two
-  // seconds has passed for the first browsing instance, and 1 second for the
-  // second browsing instance.
-  {
-    AdvanceClock(base::TimeDelta::FromSeconds(1));
-
-    base::HistogramTester tester;
-    page1->SetIsVisible(true);
-    ExpectBrowsingInstanceData(kBID1, 1, 1);
-    ExpectBrowsingInstanceData(kBID2, 1, 0);
-    tester.ExpectUniqueSample(
-        metrics_->kBrowsingInstanceDataByTimeHistogramName,
-        BrowsingInstanceDataState::kSinglePageBackground, 3);
-    tester.ExpectUniqueSample(
-        metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
-        BrowsingInstanceDataState::kSinglePageBackground, 3);
-  }
-
-  FastForwardUntilTimerFires();
-
-  // The first BI has been background for the entire time, the second one
-  // was background for 1 second, and foreground for the rest of the time.
-  histogram_tester_.ExpectTotalCount(
-      metrics_->kBrowsingInstanceDataByTimeHistogramName,
-      metrics_->kReportingInterval.InSeconds() * 2 - 1);
-  histogram_tester_.ExpectBucketCount(
-      metrics_->kBrowsingInstanceDataByTimeHistogramName,
-      BrowsingInstanceDataState::kSinglePageBackground,
-      metrics_->kReportingInterval.InSeconds() + 1);
-  histogram_tester_.ExpectBucketCount(
-      metrics_->kBrowsingInstanceDataByTimeHistogramName,
-      BrowsingInstanceDataState::kSinglePageForeground,
-      metrics_->kReportingInterval.InSeconds() - 2);
-
-  histogram_tester_.ExpectTotalCount(
-      metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
-      metrics_->kReportingInterval.InSeconds() * 2 - 1);
-  histogram_tester_.ExpectBucketCount(
-      metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
-      BrowsingInstanceDataState::kSinglePageBackground,
-      metrics_->kReportingInterval.InSeconds() + 1);
-  histogram_tester_.ExpectBucketCount(
-      metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
-      BrowsingInstanceDataState::kSinglePageForeground,
-      metrics_->kReportingInterval.InSeconds() - 2);
-
-  // Destroy the foreground page. This should trigger one more second worth
-  // of reports for both pages.
-  {
-    AdvanceClock(base::TimeDelta::FromSeconds(1));
-
-    base::HistogramTester tester;
-    frame2.reset();
-    ExpectBrowsingInstanceData(kBID1, 1, 1);
-    ExpectNoBrowsingInstanceData(kBID2);
-
-    tester.ExpectTotalCount(metrics_->kBrowsingInstanceDataByTimeHistogramName,
-                            2);
-    tester.ExpectBucketCount(metrics_->kBrowsingInstanceDataByTimeHistogramName,
-                             BrowsingInstanceDataState::kSinglePageBackground,
-                             1);
-    tester.ExpectBucketCount(metrics_->kBrowsingInstanceDataByTimeHistogramName,
-                             BrowsingInstanceDataState::kSinglePageForeground,
-                             1);
-
-    tester.ExpectTotalCount(
-        metrics_->kBrowsingInstanceDataByPageTimeHistogramName, 2);
-    tester.ExpectBucketCount(
-        metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
-        BrowsingInstanceDataState::kSinglePageBackground, 1);
-    tester.ExpectBucketCount(
-        metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
-        BrowsingInstanceDataState::kSinglePageForeground, 1);
-  }
-
-  // Create a second frame again, but in the same browsing instance as the first
-  // one. This creates a transition to a multi-page instance, so metrics are
-  // emitted. There was 1 second of the first page being visible in its own
-  // browsing instance.
-  {
-    AdvanceClock(base::TimeDelta::FromSeconds(1));
-    base::HistogramTester tester;
-    frame2 = CreateFrameNode(process.get(), page2.get(), kBID1, kSID2);
-    frame2->SetIsCurrent(true);
-    ExpectBrowsingInstanceData(kBID1, 2, 1);
-    tester.ExpectUniqueSample(
-        metrics_->kBrowsingInstanceDataByTimeHistogramName,
-        BrowsingInstanceDataState::kSinglePageForeground, 1);
-
-    tester.ExpectUniqueSample(
-        metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
-        BrowsingInstanceDataState::kSinglePageForeground, 1);
-  }
-
-  // Make the first page invisible again, and expect a transition. There was
-  // 1 second of the two pages being in a visible multi-page browsing instance.
-  {
-    AdvanceClock(base::TimeDelta::FromSeconds(1));
-    base::HistogramTester tester;
-    page1->SetIsVisible(false);
-    ExpectBrowsingInstanceData(kBID1, 2, 0);
-    tester.ExpectUniqueSample(
-        metrics_->kBrowsingInstanceDataByTimeHistogramName,
-        BrowsingInstanceDataState::kMultiPageSomeForeground, 1);
-    tester.ExpectUniqueSample(
-        metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
-        BrowsingInstanceDataState::kMultiPageSomeForeground, 2);
-  }
-
-  // Tear down all of the pages and expect the metrics to flush. There was 1
-  // more second of a multi-page browsing instance in the background.
-  {
-    AdvanceClock(base::TimeDelta::FromSeconds(1));
-    base::HistogramTester tester;
-    frame1.reset();
-    frame2.reset();
-    page1.reset();
-    page2.reset();
-    ExpectNoBrowsingInstanceData(kBID1);
-    tester.ExpectUniqueSample(
-        metrics_->kBrowsingInstanceDataByTimeHistogramName,
-        BrowsingInstanceDataState::kMultiPageBackground, 1);
-    tester.ExpectUniqueSample(
-        metrics_->kBrowsingInstanceDataByPageTimeHistogramName,
-        BrowsingInstanceDataState::kMultiPageBackground, 2);
-  }
-}
-
 }  // namespace performance_manager
diff --git a/chrome/browser/predictors/predictors_features.cc b/chrome/browser/predictors/predictors_features.cc
index c092554..1a01019b 100644
--- a/chrome/browser/predictors/predictors_features.cc
+++ b/chrome/browser/predictors/predictors_features.cc
@@ -20,4 +20,10 @@
 const base::Feature kLoadingPreconnectToRedirectTarget{
     "LoadingPreconnectToRedirectTarget", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Modifies loading predictor so that the value of the |always_access_network|
+// attribute is not used when computing the predicting score for an origin.
+const base::Feature kLoadingPredictorDisregardAlwaysAccessesNetwork{
+    "LoadingPredictorDisregardAlwaysAccessesNetwork",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace features
diff --git a/chrome/browser/predictors/predictors_features.h b/chrome/browser/predictors/predictors_features.h
index 43a75ce..da2b4c28 100644
--- a/chrome/browser/predictors/predictors_features.h
+++ b/chrome/browser/predictors/predictors_features.h
@@ -18,6 +18,8 @@
 
 extern const base::Feature kLoadingPreconnectToRedirectTarget;
 
+extern const base::Feature kLoadingPredictorDisregardAlwaysAccessesNetwork;
+
 }  // namespace features
 
 #endif  // CHROME_BROWSER_PREDICTORS_PREDICTORS_FEATURES_H_
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_tables.cc b/chrome/browser/predictors/resource_prefetch_predictor_tables.cc
index 3b1aadb..268d1f4 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_tables.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_tables.cc
@@ -11,6 +11,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
+#include "chrome/browser/predictors/predictors_features.h"
 #include "sql/statement.h"
 
 using google::protobuf::MessageLite;
@@ -110,7 +111,11 @@
   bool is_high_confidence = confidence > .75 && origin.number_of_hits() > 10;
   score += is_high_confidence * 1e6;
 
-  score += origin.always_access_network() * 1e4;
+  if (!base::FeatureList::IsEnabled(
+          features::kLoadingPredictorDisregardAlwaysAccessesNetwork)) {
+    score += origin.always_access_network() * 1e4;
+  }
+
   score += origin.accessed_network() * 1e2;
   score += 1e2 - origin.average_position();
 
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_tables_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_tables_unittest.cc
index 31c681b5..35467a1 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_tables_unittest.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_tables_unittest.cc
@@ -11,9 +11,11 @@
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "chrome/browser/predictors/loading_test_util.h"
 #include "chrome/browser/predictors/predictor_database.h"
+#include "chrome/browser/predictors/predictors_features.h"
 #include "chrome/browser/predictors/resource_prefetch_predictor_tables.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/browser_task_environment.h"
@@ -438,6 +440,51 @@
             compute_score(1, 1, 12., true, true));
 }
 
+TEST_F(ResourcePrefetchPredictorTablesTest,
+       ComputeOriginScore_LoadingPredictorDisregardAlwaysAccessesNetwork) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      features::kLoadingPredictorDisregardAlwaysAccessesNetwork);
+
+  auto compute_score = [](int hits, int misses, double average_position,
+                          bool always_access_network, bool accessed_network) {
+    OriginStat origin;
+    InitializeOriginStat(&origin, "", hits, misses, 0, average_position,
+                         always_access_network, accessed_network);
+    return ResourcePrefetchPredictorTables::ComputeOriginScore(origin);
+  };
+
+  // High-confidence is more important than the rest.
+  EXPECT_GT(compute_score(20, 2, 12., false, false),
+            compute_score(2, 0, 12., false, false));
+  EXPECT_GT(compute_score(20, 2, 12., false, false),
+            compute_score(2, 0, 2., true, true));
+
+  // Don't care about the confidence as long as it's high.
+  EXPECT_NEAR(compute_score(20, 2, 12., false, false),
+              compute_score(50, 6, 12., false, false), 1e-4);
+
+  // Mandatory network access.
+  EXPECT_EQ(compute_score(1, 1, 12., true, false),
+            compute_score(1, 1, 12., false, false));
+  EXPECT_LT(compute_score(1, 1, 12., true, false),
+            compute_score(1, 1, 12., false, true));
+  EXPECT_LT(compute_score(1, 1, 12., false, false),
+            compute_score(1, 1, 2., true, true));
+
+  // Accessed network.
+  EXPECT_GT(compute_score(1, 1, 12., false, true),
+            compute_score(1, 1, 12., false, false));
+  EXPECT_GT(compute_score(1, 1, 12., false, true),
+            compute_score(1, 1, 2., false, false));
+
+  // All else being equal, position matters.
+  EXPECT_GT(compute_score(1, 1, 2., false, false),
+            compute_score(1, 1, 12., false, false));
+  EXPECT_GT(compute_score(1, 1, 2., true, true),
+            compute_score(1, 1, 12., true, true));
+}
+
 TEST_F(ResourcePrefetchPredictorTablesTest, GetAllData) {
   TestGetAllData();
 }
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
index 80a833c..e47aec9 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
@@ -310,6 +310,72 @@
                 {{host_redirect_data.primary_key(), host_redirect_data}}));
 }
 
+// Single navigation that will be recorded. Will check for duplicate
+// resources and also for number of resources saved.
+TEST_F(ResourcePrefetchPredictorTest,
+       NavigationUrlNotInDB_LoadingPredictorDisregardAlwaysAccessesNetwork) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      features::kLoadingPredictorDisregardAlwaysAccessesNetwork);
+
+  std::vector<content::mojom::ResourceLoadInfoPtr> resources;
+  resources.push_back(CreateResourceLoadInfo("http://www.google.com"));
+  resources.push_back(CreateResourceLoadInfo(
+      "http://google.com/style1.css", content::ResourceType::kStylesheet));
+  resources.push_back(CreateResourceLoadInfo("http://google.com/script1.js",
+                                             content::ResourceType::kScript));
+  resources.push_back(CreateResourceLoadInfo("http://google.com/script2.js",
+                                             content::ResourceType::kScript));
+  resources.push_back(CreateResourceLoadInfo("http://google.com/script1.js",
+                                             content::ResourceType::kScript));
+  resources.push_back(CreateResourceLoadInfo("http://google.com/image1.png",
+                                             content::ResourceType::kImage));
+  resources.push_back(CreateResourceLoadInfo("http://google.com/image2.png",
+                                             content::ResourceType::kImage));
+  resources.push_back(CreateResourceLoadInfo(
+      "http://google.com/style2.css", content::ResourceType::kStylesheet));
+  resources.push_back(
+      CreateResourceLoadInfo("http://static.google.com/style2-no-store.css",
+                             content::ResourceType::kStylesheet,
+                             /* always_access_network */ true));
+  resources.push_back(CreateResourceLoadInfoWithRedirects(
+      {"http://reader.google.com/style.css",
+       "http://dev.null.google.com/style.css"},
+      content::ResourceType::kStylesheet));
+  resources.back()->network_info->always_access_network = true;
+
+  auto page_summary = CreatePageRequestSummary(
+      "http://www.google.com", "http://www.google.com", resources);
+
+  StrictMock<MockResourcePrefetchPredictorObserver> mock_observer(predictor_);
+  EXPECT_CALL(mock_observer, OnNavigationLearned(page_summary));
+
+  predictor_->RecordPageRequestSummary(
+      std::make_unique<PageRequestSummary>(page_summary));
+  profile_->BlockUntilHistoryProcessesPendingRequests();
+
+  OriginData origin_data = CreateOriginData("www.google.com");
+  InitializeOriginStat(origin_data.add_origins(), "http://www.google.com/", 1,
+                       0, 0, 1., false, true);
+  InitializeOriginStat(origin_data.add_origins(), "http://google.com/", 1, 0, 0,
+                       2., false, true);
+  InitializeOriginStat(origin_data.add_origins(), "http://static.google.com/",
+                       1, 0, 0, 3., true, true);
+  InitializeOriginStat(origin_data.add_origins(), "http://reader.google.com/",
+                       1, 0, 0, 4., false, true);
+  InitializeOriginStat(origin_data.add_origins(), "http://dev.null.google.com/",
+                       1, 0, 0, 5., true, true);
+  EXPECT_EQ(mock_tables_->origin_table_.data_,
+            OriginDataMap({{origin_data.host(), origin_data}}));
+
+  RedirectData host_redirect_data = CreateRedirectData("www.google.com");
+  InitializeRedirectStat(host_redirect_data.add_redirect_endpoints(),
+                         GURL("http://www.google.com"), 1, 0, 0);
+  EXPECT_EQ(mock_tables_->host_redirect_table_.data_,
+            RedirectDataMap(
+                {{host_redirect_data.primary_key(), host_redirect_data}}));
+}
+
 // Tests that navigation is recorded correctly for URL already present in
 // the database cache.
 TEST_F(ResourcePrefetchPredictorTest, NavigationUrlInDB) {
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
index 20199b34..4a0f2d15 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -393,6 +393,13 @@
      */
     public static final String OFFLINE_INDICATOR_V2_ENABLED = "offline_indicator_v2_enabled";
 
+    public static final String PRIVACY_METRICS_REPORTING = "metrics_reporting";
+    public static final String PRIVACY_METRICS_IN_SAMPLE = "in_metrics_sample";
+    public static final String PRIVACY_NETWORK_PREDICTIONS = "network_predictions";
+    public static final String PRIVACY_BANDWIDTH_OLD = "prefetch_bandwidth";
+    public static final String PRIVACY_BANDWIDTH_NO_CELLULAR_OLD = "prefetch_bandwidth_no_cellular";
+    public static final String PRIVACY_ALLOW_PRERENDER_OLD = "allow_prefetch";
+
     /**
      * Whether the promotion for data reduction has been skipped on first invocation.
      * Default value is false.
@@ -643,6 +650,12 @@
                 HOMEPAGE_USE_DEFAULT_URI,
                 LATEST_UNSUPPORTED_VERSION,
                 OFFLINE_INDICATOR_V2_ENABLED,
+                PRIVACY_ALLOW_PRERENDER_OLD,
+                PRIVACY_BANDWIDTH_NO_CELLULAR_OLD,
+                PRIVACY_BANDWIDTH_OLD,
+                PRIVACY_METRICS_IN_SAMPLE,
+                PRIVACY_METRICS_REPORTING,
+                PRIVACY_NETWORK_PREDICTIONS,
                 PROMOS_SKIPPED_ON_FIRST_START,
                 REACHED_CODE_PROFILER_GROUP,
                 SIGNIN_AND_SYNC_PROMO_SHOW_COUNT,
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index e37bf01..9464bb4f 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -444,6 +444,7 @@
     "$root_gen_dir/chrome/quota_internals_resources.pak",
     "$root_gen_dir/chrome/usb_internals_resources.pak",
     "$root_gen_dir/chrome/webrtc_logs_resources.pak",
+    "$root_gen_dir/components/dev_ui_components_resources.pak",
     "$root_gen_dir/components/sync_driver_resources.pak",
     "$root_gen_dir/content/browser/resources/media/media_internals_resources.pak",
     "$root_gen_dir/content/browser/webrtc/resources/webrtc_internals_resources.pak",
@@ -457,6 +458,7 @@
     "//chrome/browser/resources/omnibox:resources",
     "//chrome/browser/resources/quota_internals:quota_internals_resources",
     "//chrome/browser/resources/usb_internals:resources",
+    "//components/resources:dev_ui_components_resources",
     "//components/sync/driver:resources",
     "//content/browser/resources/media:media_internals_resources",
     "//content/browser/webrtc/resources",
diff --git a/chrome/browser/resources/discards/database_tab.html b/chrome/browser/resources/discards/database_tab.html
index a011dcf..b590501 100644
--- a/chrome/browser/resources/discards/database_tab.html
+++ b/chrome/browser/resources/discards/database_tab.html
@@ -1,4 +1,10 @@
     <style>
+      @media (prefers-color-scheme: dark) {
+        :host {
+          color: var(--cr-secondary-text-color);
+        }
+      }
+
       .add-origin-container {
         display: flex;
         padding-top: 10px;
@@ -17,6 +23,7 @@
 
       table th {
         background: rgb(224, 236, 255);
+        color: black;
         padding-bottom: 4px;
         padding-inline-end: 16px;
         padding-top: 4px;
diff --git a/chrome/browser/resources/discards/discards.html b/chrome/browser/resources/discards/discards.html
index 9874bc6..7f82d1e 100644
--- a/chrome/browser/resources/discards/discards.html
+++ b/chrome/browser/resources/discards/discards.html
@@ -10,6 +10,7 @@
   <head>
     <title>Discards</title>
     <meta charset="utf-8">
+    <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
     <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
     <style>
       html,
@@ -18,6 +19,12 @@
         overflow: hidden;
       }
 
+      @media (prefers-color-scheme: dark) {
+        body {
+          background-color: var(--md-background-color);
+        }
+      }
+
       body {
         margin: 0;
       }
diff --git a/chrome/browser/resources/discards/discards_tab.html b/chrome/browser/resources/discards/discards_tab.html
index 9eb2fac..4b353eb 100644
--- a/chrome/browser/resources/discards/discards_tab.html
+++ b/chrome/browser/resources/discards/discards_tab.html
@@ -11,6 +11,13 @@
         padding-right: 4px;
       }
 
+      @media (prefers-color-scheme: dark) {
+        table td,
+        table th {
+          border-color: var(--cr-separator-color);
+        }
+      }
+
       table th {
         background: rgb(224, 236, 255);
         padding-bottom: 4px;
@@ -29,6 +36,13 @@
         justify-content: flex-start;
       }
 
+      @media (prefers-color-scheme: dark) {
+        table td {
+          background-color: var(--google-grey-900);
+          color: var(--cr-secondary-text-color);
+        }
+      }
+
       table td.title-cell {
         max-width: 200px;
         overflow: hidden;
@@ -87,6 +101,12 @@
         background: rgb(255, 255, 187);
       }
 
+      @media (prefers-color-scheme: dark) {
+        table tr:hover td {
+          background: var(--google-grey-800);
+        }
+      }
+
       th div.header-cell-container::after {
         content: '▲';
         opacity: 0;
diff --git a/chrome/browser/resources/new_tab_page/customize_dialog.html b/chrome/browser/resources/new_tab_page/customize_dialog.html
index a2cf964..b64a54d 100644
--- a/chrome/browser/resources/new_tab_page/customize_dialog.html
+++ b/chrome/browser/resources/new_tab_page/customize_dialog.html
@@ -61,13 +61,24 @@
     display: inline-grid;
     grid-column-gap: 25px;
     grid-row-gap: 25px;
-    grid-template-columns: repeat(6, auto);
+    grid-template-columns: repeat(var(--num-theme-columns), auto);
+    outline-width: 0;
+    padding: 3px;
     width: fit-content;
   }
 
+  :host-context(.focus-outline-visible) #themesContainer:focus {
+    box-shadow: inset 0 0 0 2px rgba(var(--google-blue-600-rgb), .4);
+  }
+
   ntp-theme-icon {
     align-self: center;
     justify-self: center;
+    outline-width: 0;
+  }
+
+  :host-context(.focus-outline-visible) ntp-theme-icon:focus {
+    box-shadow: 0 0 0 2px rgba(var(--google-blue-600-rgb), .4);
   }
 
   #autogeneratedTheme {
@@ -106,7 +117,8 @@
     <input id="colorPicker" type="color" on-change="onCustomFrameColorChange_"
         hidden>
     </input>
-    <div id="themesContainer">
+    <div id="themesContainer" on-keydown="onThemesKeyDown_"
+        style="--num-theme-columns: [[numThemeColumns_]];">
       <!-- TODO(crbug.com/1032327): Add color picker icon. -->
       <ntp-theme-icon id="autogeneratedTheme" title="$i18n{colorPickerLabel}"
           on-click="onAutogeneratedThemeClick_"
diff --git a/chrome/browser/resources/new_tab_page/customize_dialog.js b/chrome/browser/resources/new_tab_page/customize_dialog.js
index e336613..8d425f5 100644
--- a/chrome/browser/resources/new_tab_page/customize_dialog.js
+++ b/chrome/browser/resources/new_tab_page/customize_dialog.js
@@ -14,7 +14,6 @@
 /**
  * Dialog that lets the user customize the NTP such as the background color or
  * image.
- * TODO(crbug.com/1032327): Add keyboard support.
  * TODO(crbug.com/1032328): Add support for selecting background image.
  * TODO(crbug.com/1032333): Add support for selecting shortcuts vs most visited.
  */
@@ -37,6 +36,13 @@
 
       /** @private {!Array<!newTabPage.mojom.ChromeTheme>} */
       chromeThemes_: Array,
+
+      /** @private {number} */
+      numThemeColumns_: {
+        type: Number,
+        readOnly: true,
+        value: 6,
+      },
     };
   }
 
@@ -168,6 +174,46 @@
   skColorToRgb_(skColor) {
     return skColorToRgb(skColor);
   }
+
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onThemesKeyDown_(e) {
+    if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(e.key)) {
+      e.preventDefault();
+      const themeIcons =
+          Array.from(this.$.themesContainer.querySelectorAll('ntp-theme-icon'));
+      const currentIndex = themeIcons.indexOf(e.target);
+      const isRtl = window.getComputedStyle(this)['direction'] === 'rtl';
+      let delta = 0;
+      switch (e.key) {
+        case 'ArrowLeft':
+          delta = isRtl ? 1 : -1;
+          break;
+        case 'ArrowRight':
+          delta = isRtl ? -1 : 1;
+          break;
+        case 'ArrowUp':
+          delta = -this.numThemeColumns_;
+          break;
+        case 'ArrowDown':
+          delta = this.numThemeColumns_;
+          break;
+      }
+      const mod = function(m, n) {
+        return ((m % n) + n) % n;
+      };
+      const newIndex = mod(currentIndex + delta, themeIcons.length);
+      themeIcons[newIndex].focus();
+    }
+
+    if (['Enter', ' '].includes(e.key)) {
+      e.preventDefault();
+      e.stopPropagation();
+      e.target.click();
+    }
+  }
 }
 
 customElements.define(CustomizeDialogElement.is, CustomizeDialogElement);
diff --git a/chrome/browser/resources/new_tab_page/theme_icon.js b/chrome/browser/resources/new_tab_page/theme_icon.js
index 81708280..e48fab8 100644
--- a/chrome/browser/resources/new_tab_page/theme_icon.js
+++ b/chrome/browser/resources/new_tab_page/theme_icon.js
@@ -18,6 +18,17 @@
   static get template() {
     return html`{__html_template__}`;
   }
+
+  static get properties() {
+    return {
+      /** @type {number} */
+      tabindex: {
+        type: Number,
+        reflectToAttribute: true,
+        value: 0,
+      },
+    };
+  }
 }
 
 customElements.define(ThemeIconElement.is, ThemeIconElement);
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.js b/chrome/browser/resources/settings/basic_page/basic_page.js
index f30d89c3..5c65cb2e 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.js
+++ b/chrome/browser/resources/settings/basic_page/basic_page.js
@@ -233,11 +233,6 @@
     if (!this.prefs || !this.currentRoute_) {
       return;
     }
-    // Don't show the banner when SplitSettings is disabled (and hence this page
-    // is already showing OS settings).
-    if (loadTimeData.getBoolean('showOSSettings')) {
-      return false;
-    }
     const showPref = /** @type {boolean} */ (
         this.getPref('settings.cros.show_os_banner').value);
 
diff --git a/chrome/browser/resources/settings/images/cookies_banner.svg b/chrome/browser/resources/settings/images/cookies_banner.svg
new file mode 100644
index 0000000..61cb962
--- /dev/null
+++ b/chrome/browser/resources/settings/images/cookies_banner.svg
@@ -0,0 +1 @@
+<svg width="419" height="126" viewBox="0 0 419 126" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient x1="100%" y1="50%" x2="0%" y2="50%" id="a"><stop stop-color="#D6D6D7" offset="0%"/><stop stop-color="#FFF" stop-opacity="0" offset="100%"/></linearGradient><path d="M0 0h193v4a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V0z" id="b"/><path d="M3.375 0h91.25A3.375 3.375 0 0 1 98 3.375v53.25A3.375 3.375 0 0 1 94.625 60H3.375A3.375 3.375 0 0 1 0 56.625V3.375A3.375 3.375 0 0 1 3.375 0z" id="c"/><linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="f"><stop stop-opacity="0" offset="0%"/><stop stop-opacity=".5" offset="100%"/></linearGradient><path d="M16 31.988c-4.34 0-8.402-1.7-11.438-4.787a15.761 15.761 0 0 1-4.56-11.396c.004-.226.083-.442.226-.617a1.06 1.06 0 0 1 .541-.352 4.72 4.72 0 0 0 3.036-2.418.998.998 0 0 1 1.243-.477c3.23 1.223 6.372-1.25 6.372-4.392 0-.102-.016-.199-.029-.296l-.027-.21a1.003 1.003 0 0 1 .96-1.11 4.708 4.708 0 0 0 4.42-3.604c.3-1.264 1.598-2.045 2.91-1.742C26.924 2.28 32 8.646 32 16.073c0 8.774-7.178 15.915-16 15.915z" id="e"/><path d="M12 1.988c-.26 0-.52-.11-.71-.29-.18-.19-.29-.45-.29-.71 0-.26.11-.52.29-.71.38-.37 1.05-.37 1.42 0 .18.19.29.44.29.71 0 .26-.11.52-.29.71-.19.18-.45.29-.71.29z" id="h"/><filter x="-12.5%" y="-12.6%" width="150%" height="150.3%" filterUnits="objectBoundingBox" id="g"><feOffset dx=".5" dy=".5" in="SourceAlpha" result="shadowOffsetOuter1"/><feColorMatrix values="0 0 0 0 0.968627451 0 0 0 0 0.725490196 0 0 0 0 0.0117647059 0 0 0 1 0" in="shadowOffsetOuter1"/></filter><path d="M26 18.988c-.26 0-.52-.11-.71-.29-.18-.19-.29-.45-.29-.71 0-.26.11-.521.29-.71.38-.37 1.04-.37 1.42 0 .19.189.29.45.29.71 0 .26-.11.52-.29.71-.19.18-.45.29-.71.29z" id="i"/><filter x="-12.5%" y="-12.6%" width="125%" height="125.2%" filterUnits="objectBoundingBox" id="j"><feOffset dx=".5" dy=".5" in="SourceAlpha" result="shadowOffsetInner1"/><feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" in="shadowInnerInner1"/></filter><path d="M22 15.988c-.26 0-.52-.11-.71-.29-.18-.19-.29-.45-.29-.71 0-.26.11-.52.29-.71.37-.37 1.05-.37 1.42 0 .18.19.29.45.29.71 0 .26-.11.52-.29.71-.19.18-.45.29-.71.29z" id="k"/><filter x="-12.5%" y="-12.6%" width="125%" height="125.2%" filterUnits="objectBoundingBox" id="l"><feOffset dx=".5" dy=".5" in="SourceAlpha" result="shadowOffsetInner1"/><feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" in="shadowInnerInner1"/></filter><path d="M15 14.988c-.26 0-.52-.11-.71-.29-.18-.19-.29-.45-.29-.71 0-.26.11-.52.29-.71.38-.37 1.05-.37 1.42 0 .18.19.29.45.29.71 0 .26-.11.52-.29.71-.19.18-.45.29-.71.29z" id="m"/><filter x="-12.5%" y="-12.6%" width="125%" height="125.2%" filterUnits="objectBoundingBox" id="n"><feOffset dx=".5" dy=".5" in="SourceAlpha" result="shadowOffsetInner1"/><feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" in="shadowInnerInner1"/></filter><path d="M12 25.988c-.26 0-.52-.11-.71-.29-.18-.19-.29-.45-.29-.71 0-.26.11-.521.29-.71.37-.37 1.05-.37 1.42 0 .18.189.29.45.29.71 0 .26-.11.52-.29.71-.19.18-.44.29-.71.29z" id="o"/><filter x="-12.5%" y="-12.6%" width="125%" height="125.2%" filterUnits="objectBoundingBox" id="p"><feOffset dx=".5" dy=".5" in="SourceAlpha" result="shadowOffsetInner1"/><feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" in="shadowInnerInner1"/></filter><circle id="r" cx="5.5" cy="7.487" r="1.5"/><filter x="-8.3%" y="-8.3%" width="133.3%" height="133.3%" filterUnits="objectBoundingBox" id="q"><feOffset dx=".5" dy=".5" in="SourceAlpha" result="shadowOffsetOuter1"/><feColorMatrix values="0 0 0 0 0.968627451 0 0 0 0 0.725490196 0 0 0 0 0.0117647059 0 0 0 1 0" in="shadowOffsetOuter1"/></filter><circle id="s" cx="20.5" cy="9.488" r="1.5"/><filter x="-8.3%" y="-8.3%" width="116.7%" height="116.7%" filterUnits="objectBoundingBox" id="t"><feOffset dx=".5" dy=".5" in="SourceAlpha" result="shadowOffsetInner1"/><feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" in="shadowInnerInner1"/></filter><circle id="u" cx="19.5" cy="23.488" r="1.5"/><filter x="-8.3%" y="-8.3%" width="116.7%" height="116.7%" filterUnits="objectBoundingBox" id="v"><feOffset dx=".5" dy=".5" in="SourceAlpha" result="shadowOffsetInner1"/><feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" in="shadowInnerInner1"/></filter><circle id="w" cx="8.5" cy="18.488" r="1.5"/><filter x="-8.3%" y="-8.3%" width="116.7%" height="116.7%" filterUnits="objectBoundingBox" id="x"><feOffset dx=".5" dy=".5" in="SourceAlpha" result="shadowOffsetInner1"/><feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" in="shadowInnerInner1"/></filter></defs><g fill="none" fill-rule="evenodd"><path fill="url(#a)" transform="rotate(-180 370.809 111.968)" d="M318.309 108.968h105v6h-105z"/><g transform="translate(299 37)"><path d="M43.247 1c8.307 0 15.042 6.735 15.042 15.042v9.959a5.092 5.092 0 0 1-5.092 5.092H33.279A5.092 5.092 0 0 1 28.187 26v-9.959C28.187 7.735 34.922 1 43.23 1h.018z" stroke="#F5F5F7" stroke-width="2"/><path d="M65 77V15H48v62h17z" stroke="#E8EAED" stroke-width="2" fill="#FFF" fill-rule="nonzero"/><path d="M57.5 67.858v-50.97l1.134-.529L56.5 15v55l2.336-1.246-1.336-.896z" stroke="#E8EAED" stroke-width="3" fill="#FFF" fill-rule="nonzero"/><path d="M25.235 0h0c8.307 0 15.042 6.735 15.042 15.042v9.959a5.092 5.092 0 0 1-5.092 5.092H15.267A5.092 5.092 0 0 1 10.175 25v-9.959C10.175 6.735 16.91 0 25.217 0h.018z" stroke="#E8EAED" stroke-width="2"/><rect stroke="#E8EAED" stroke-width="2" fill="#F8F9FA" fill-rule="nonzero" x="1" y="15" width="48" height="62" rx="2"/></g><g transform="translate(42 14)"><path fill="url(#a)" d="M0 95h105v6H0z"/><path d="M105 1a7 7 0 0 0-7 7v85a7 7 0 0 0 7 7h124a7 7 0 0 0 7-7V8a7 7 0 0 0-7-7H105z" stroke="#E8EAED" stroke-width="2"/><path d="M100 93h47v6h-45a2 2 0 0 1-2-2v-4z" fill="#F8F9FA"/><rect stroke="#E8EAED" stroke-width="2" x="106" y="8" width="122" height="78" rx="1"/><path d="M99 93h47l2 6h-47a2 2 0 0 1-2-2v-4z" fill="#F8F9FA"/><path d="M223 92h66v3a5 5 0 0 1-5 5h-61v-8z" fill="#FFF"/><path stroke="#E8EAED" stroke-width="2" d="M98 92v3a5 5 0 0 0 5 5h181a5 5 0 0 0 5-5v-3H98zM146.32 92.403c0 5.065 2.182 7.597 6.547 7.597"/><path d="M199 91h32v2a3 3 0 0 1-3 3h-26a3 3 0 0 1-3-3v-2z" fill="#E8EAED"/></g><rect stroke="#E8EAED" stroke-width="2" fill-opacity=".2" fill="#FBBC04" x="148" y="22" width="122" height="78" rx="1"/><g transform="translate(160 31)"><mask id="d" fill="#fff"><use xlink:href="#c"/></mask><use fill="#FFF" fill-rule="nonzero" transform="matrix(1 0 0 -1 0 60)" xlink:href="#c"/><g mask="url(#d)" fill-rule="nonzero"><g transform="translate(33 18)"><use fill="#FBBC04" xlink:href="#e"/><use fill-opacity=".15" fill="url(#f)" xlink:href="#e"/></g><g transform="translate(33 18)"><use fill="#000" filter="url(#g)" xlink:href="#h"/><use fill="#572A07" xlink:href="#h"/></g><g transform="translate(33 18)"><use fill="#572A07" xlink:href="#i"/><use fill="#000" filter="url(#j)" xlink:href="#i"/></g><g transform="translate(33 18)"><use fill="#572A07" xlink:href="#k"/><use fill="#000" filter="url(#l)" xlink:href="#k"/></g><g transform="translate(33 18)"><use fill="#572A07" xlink:href="#m"/><use fill="#000" filter="url(#n)" xlink:href="#m"/></g><path d="M48 37.987c-.26 0-.52-.11-.71-.29-.18-.19-.29-.45-.29-.71 0-.26.11-.52.29-.71.38-.37 1.04-.37 1.42 0 .18.19.29.44.29.71 0 .27-.11.52-.29.71-.19.18-.45.29-.71.29z" fill="#572A07"/><g transform="translate(33 18)"><use fill="#572A07" xlink:href="#o"/><use fill="#000" filter="url(#p)" xlink:href="#o"/></g><g transform="translate(33 18)"><use fill="#000" filter="url(#q)" xlink:href="#r"/><use fill="#572A07" xlink:href="#r"/></g><g transform="translate(33 18)"><use fill="#572A07" xlink:href="#s"/><use fill="#000" filter="url(#t)" xlink:href="#s"/></g><g transform="translate(33 18)"><use fill="#572A07" xlink:href="#u"/><use fill="#000" filter="url(#v)" xlink:href="#u"/></g><g transform="translate(33 18)"><use fill="#572A07" xlink:href="#w"/><use fill="#000" filter="url(#x)" xlink:href="#w"/></g></g><rect fill="#FBBC04" mask="url(#d)" x="-1.125" width="101.375" height="9" rx="2.25"/><ellipse fill="#572A07" mask="url(#d)" cx="49.5" cy="63.625" rx="5.625" ry="1.125"/><circle fill="#FFF" mask="url(#d)" cx="5.063" cy="5.063" r="1.688"/></g><g transform="translate(52 21)"><path fill="#F1F1F3" fill-rule="nonzero" d="M26.491 65.805l.845-54.408h1.43l.85 54.408z"/><path d="M28.051 49.903a6.346 6.346 0 0 0-6.345-6.35" stroke="#F1F1F3" stroke-width="1.541"/><path d="M20.472 31.485c.763.624.806 1.954 1.411 2.645.605.691 1.959.994 2.4 1.78.48.87.039 2.113.288 2.972.279.984 1.287 1.858 1.195 2.74-.1.985-1.257 1.537-1.857 2.276-.6.74-.922 1.978-1.867 2.266-.85.264-1.92-.557-2.924-.639-.892-.072-2.016.624-2.97.298-.86-.293-1.354-1.526-2.218-2.02-.864-.495-2.108-.24-2.88-.865-.773-.624-.807-1.949-1.412-2.645-.604-.696-1.958-.988-2.4-1.776-.504-.873-.043-2.112-.288-2.97-.278-.99-1.286-1.863-1.195-2.746.096-.984 1.258-1.536 1.858-2.27.6-.735.921-1.978 1.867-2.271.85-.26 1.92.557 2.923.638.893.077 2.016-.624 2.971-.297.86.292 1.354 1.526 2.218 2.02.864.495 2.122.24 2.88.864z" fill="#F1F1F3" fill-rule="nonzero"/><path d="M28.051 49.903a6.35 6.35 0 0 1 6.35-6.35" stroke="#F1F1F3" stroke-width="1.541"/><path d="M35.63 31.485c-.758.624-.801 1.954-1.406 2.645-.605.691-1.958.994-2.4 1.78-.509.87-.043 2.113-.288 2.972-.283.984-1.286 1.858-1.2 2.74.1.985 1.258 1.537 1.862 2.276.605.74.917 1.978 1.868 2.266.844.264 1.92-.557 2.923-.639.888-.072 2.016.624 2.971.298.86-.293 1.354-1.526 2.213-2.02.859-.495 2.112-.24 2.88-.865.768-.624.801-1.949 1.406-2.645.605-.696 1.959-.988 2.4-1.776.509-.873.043-2.112.288-2.97.283-.99 1.291-1.863 1.2-2.746-.1-.984-1.257-1.536-1.862-2.27-.605-.735-.917-1.978-1.867-2.271-.845-.26-1.92.557-2.924.638-.888.077-2.016-.624-2.97-.297-.86.292-1.354 1.526-2.214 2.02-.859.495-2.121.24-2.88.864z" fill="#F1F1F3" fill-rule="nonzero"/><path d="M28.051 30.506a5.117 5.117 0 0 0-5.121-5.121" stroke="#F1F1F3" stroke-width="1.541"/><path d="M21.931 15.645c.615.504.648 1.575 1.138 2.136.49.562 1.584.802 1.949 1.44.408.706.033 1.704.235 2.4.225.797 1.037 1.503.96 2.213-.077.797-1.013 1.243-1.503 1.839-.49.595-.739 1.598-1.507 1.828-.681.212-1.536-.446-2.357-.513-.72-.058-1.632.504-2.4.24-.696-.235-1.094-1.234-1.79-1.632-.696-.399-1.704-.192-2.314-.696-.61-.504-.652-1.58-1.137-2.136-.485-.557-1.584-.802-1.949-1.44-.413-.706-.038-1.71-.235-2.4-.226-.797-1.042-1.503-.96-2.218.077-.792 1.013-1.238 1.502-1.833.49-.596.74-1.599 1.503-1.834.686-.206 1.54.451 2.361.518.72.058 1.632-.48 2.4-.24s1.095 1.234 1.79 1.632c.697.399 1.705.192 2.314.696z" fill="#F1F1F3" fill-rule="nonzero"/><path d="M28.051 30.506a5.122 5.122 0 0 1 5.127-5.121" stroke="#F1F1F3" stroke-width="1.541"/><path d="M34.171 15.645c-.614.504-.648 1.575-1.137 2.136-.49.562-1.58.802-1.95 1.44-.407.706-.033 1.704-.23 2.4-.225.797-1.041 1.503-.96 2.213.082.797 1.018 1.243 1.503 1.839.485.595.744 1.598 1.507 1.828.686.212 1.536-.446 2.362-.513.72-.058 1.627.504 2.4.24.69-.235 1.09-1.234 1.785-1.632.696-.399 1.704-.192 2.319-.696.614-.504.648-1.58 1.137-2.136.49-.557 1.58-.802 1.949-1.44.408-.706.034-1.71.23-2.4.23-.797 1.042-1.503.96-2.218-.081-.792-1.017-1.238-1.502-1.833-.485-.596-.744-1.599-1.507-1.834-.682-.206-1.536.451-2.362.518-.72.058-1.627-.48-2.4-.24-.773.24-1.094 1.234-1.79 1.632-.696.399-1.7.192-2.314.696zM23.194 7.11c0 .644.662 1.215.763 1.81.1.596-.303 1.407-.091 1.964.21.557 1.056.897 1.392 1.377.384.552.417 1.44.902 1.748.485.307 1.3 0 1.92 0 .62 0 1.387.35 1.92 0 .533-.35.48-1.2.883-1.757.331-.48 1.152-.768 1.378-1.387.225-.62-.216-1.32-.11-1.964.105-.643.748-1.176.748-1.819s-.662-1.214-.768-1.81c-.105-.595.307-1.406.096-1.967-.211-.562-1.046-.922-1.382-1.402-.336-.48-.413-1.44-.898-1.747-.485-.307-1.305 0-1.92 0-.614 0-1.387-.35-1.92 0-.533.35-.504 1.2-.883 1.757-.331.48-1.152.768-1.382 1.387-.23.619.22 1.32.115 1.963-.106.643-.768 1.2-.763 1.848z" fill="#F1F1F3" fill-rule="nonzero"/><path d="M46.464 93H9.638a2.821 2.821 0 0 1-2.822-2.586l-2.65-34.395a2.794 2.794 0 0 1 .748-2.118A2.85 2.85 0 0 1 6.989 53h42.125c.788 0 1.54.326 2.076.9.536.572.806 1.34.746 2.12l-2.65 34.394A2.816 2.816 0 0 1 46.464 93z" stroke="#E8EAED" stroke-width="2" fill="#F8F9FA" fill-rule="nonzero"/><rect stroke="#E8EAED" stroke-width="2" fill="#FFF" fill-rule="nonzero" y="50.546" width="56.102" height="8.203" rx="1.781"/></g></g></svg>
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/images/permissions_banner.svg b/chrome/browser/resources/settings/images/permissions_banner.svg
new file mode 100644
index 0000000..7aa2fb4c
--- /dev/null
+++ b/chrome/browser/resources/settings/images/permissions_banner.svg
@@ -0,0 +1 @@
+<svg width="419" height="126" viewBox="0 0 419 126" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient x1="100%" y1="50%" x2="0%" y2="50%" id="a"><stop stop-color="#D6D6D7" offset="0%"/><stop stop-color="#FFF" stop-opacity="0" offset="100%"/></linearGradient><path d="M0 0h193v4a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V0z" id="b"/><linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="d"><stop stop-color="#367CEA" offset="0%"/><stop stop-color="#2570DC" offset="100%"/></linearGradient><path d="M76 0a4 4 0 0 1 4 4v39.5a4 4 0 0 1-4 4H49.133C44.928 48.585 42.343 53 40 53c-2.344 0-5.172-4.418-9.227-5.502L4 47.5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4h72z" id="c"/><path d="M33.266 4.358h-7.669l-1.47-2.708C23.573.638 22.442 0 21.206 0h-6.89c-1.239 0-2.37.642-2.922 1.656l-1.47 2.709H2.255C1.01 4.368.002 5.292 0 6.43v17.207c.004 1.138 1.011 2.06 2.255 2.064h31.01c1.245-.003 2.252-.926 2.256-2.064V6.425c-.003-1.14-1.01-2.063-2.255-2.067z" id="f"/><linearGradient x1="50.058%" y1="66.069%" x2="50.058%" y2="-31.653%" id="h"><stop stop-color="#DADCE0" stop-opacity="0" offset="0%"/><stop stop-color="#DADCE0" offset="100%"/></linearGradient><linearGradient x1="-.004%" y1="49.947%" x2="98.708%" y2="49.947%" id="i"><stop stop-color="#202124" stop-opacity="0" offset="0%"/><stop stop-color="#202124" offset="20.861%"/><stop stop-color="#202124" stop-opacity=".97" offset="77.708%"/><stop stop-color="#202124" stop-opacity="0" offset="100%"/></linearGradient><path d="M9.588 0a6.016 6.016 0 0 1 6.016 6.016v4.834c-6.016.023-3.003.023-12.032.023V6.016A6.016 6.016 0 0 1 9.588 0z" id="j"/><linearGradient x1="115.776%" y1="33.255%" x2="-176.007%" y2="169.271%" id="m"><stop stop-color="#FBBC05" offset="0%"/><stop stop-color="#FBBC05" offset="24.264%"/><stop stop-color="#FBBC05" offset="100%"/></linearGradient><path d="M15.603 10.873l.001 4.167a6.016 6.016 0 0 1-12.032 0v-4.167h12.031z" id="l"/><linearGradient x1="42.748%" y1="59.913%" x2="-121.122%" y2="45.403%" id="o"><stop stop-color="#FFF" offset="0%"/><stop stop-color="#D7DADD" offset="24.264%"/><stop stop-color="#BDC1C5" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><g transform="translate(42 14)"><path fill="url(#a)" d="M0 95h105v6H0z"/><path d="M105 1a7 7 0 0 0-7 7v85a7 7 0 0 0 7 7h124a7 7 0 0 0 7-7V8a7 7 0 0 0-7-7H105z" stroke="#E8EAED" stroke-width="2"/><path d="M100 93h47v6h-45a2 2 0 0 1-2-2v-4z" fill="#F8F9FA"/><rect stroke="#E8EAED" stroke-width="2" x="106" y="8" width="122" height="78" rx="1"/><path d="M99 93h47l2 6h-47a2 2 0 0 1-2-2v-4z" fill="#F8F9FA"/><path d="M223 92h66v3a5 5 0 0 1-5 5h-61v-8z" fill="#FFF"/><path stroke="#E8EAED" stroke-width="2" d="M98 92v3a5 5 0 0 0 5 5h181a5 5 0 0 0 5-5v-3H98zM146.32 92.403c0 5.065 2.182 7.597 6.547 7.597"/><path d="M199 91h32v2a3 3 0 0 1-3 3h-26a3 3 0 0 1-3-3v-2z" fill="#E8EAED"/></g><rect stroke="#E8EAED" stroke-width="2" fill-opacity=".2" fill="#4285F4" x="148" y="22" width="122" height="78" rx="1"/><circle fill="#FFF" cx="209" cy="19" r="2"/><g transform="translate(169 34)"><mask id="e" fill="#fff"><use xlink:href="#c"/></mask><g fill-rule="nonzero" transform="matrix(1 0 0 -1 0 53)"><use fill="#D2DFF5" xlink:href="#c"/><use fill="url(#d)" xlink:href="#c"/></g><g mask="url(#e)"><g transform="translate(23 16)"><mask id="g" fill="#fff"><use xlink:href="#f"/></mask><use fill="#F8F9FA" fill-rule="nonzero" xlink:href="#f"/><path fill="#DADCE0" mask="url(#g)" d="M5-3h25v7.3H5z"/><circle fill="#2A2C33" mask="url(#g)" cx="17.357" cy="14.792" r="7"/><circle fill="#F8F9FA" fill-rule="nonzero" mask="url(#g)" cx="15" cy="13" r="1"/></g></g></g><path d="M326.013 59.2h-.045a2.82 2.82 0 0 1-2.165-1.421c-1.42-2.625-4.412-4.112-7.473-3.715-3.06.396-5.53 2.59-6.17 5.483-.641 2.891.687 5.856 3.317 7.407 2.63 1.55 5.994 1.352 8.405-.496 1.338 1.494 3.547 1.96 5.418 1.144 1.87-.817 2.951-2.72 2.65-4.666-.302-1.946-1.912-3.467-3.95-3.73l.013-.005z" fill="url(#h)" fill-rule="nonzero"/><path d="M303.8 44.076h22c2.095 0 3.79-.912 5.986-2.776 2.703-2.294 2.712-2.3 3.214-2.3.487 0 .288-.153 3.107 2.293 2.14 1.857 3.885 2.783 6.093 2.783h20a3.8 3.8 0 0 1 3.8 3.8V79.2a3.8 3.8 0 0 1-3.8 3.8h-60.4a3.8 3.8 0 0 1-3.8-3.8V47.876a3.8 3.8 0 0 1 3.8-3.8z" stroke="#E8EAED" stroke-width="2" fill="#F8F9FA" fill-rule="nonzero"/><path fill="url(#i)" fill-rule="nonzero" opacity=".04" transform="rotate(-180 334.5 77.8)" d="M323 77h23v1.6h-23z"/><g fill-rule="nonzero"><path d="M53.8 44.076h22c2.095 0 3.79-.912 5.986-2.776C84.49 39.006 84.498 39 85 39c.487 0 .288-.153 3.107 2.293 2.14 1.857 3.885 2.783 6.093 2.783h20a3.8 3.8 0 0 1 3.8 3.8V79.2a3.8 3.8 0 0 1-3.8 3.8H53.8a3.8 3.8 0 0 1-3.8-3.8V47.876a3.8 3.8 0 0 1 3.8-3.8z" stroke="#E8EAED" stroke-width="2" fill="#F8F9FA"/><path fill="url(#i)" opacity=".04" transform="rotate(-180 47.5 49.3)" d="M0 23h23v1.6H0z"/><path d="M83.803 51a8.777 8.777 0 0 0-8.788 8.788c0 1.695.541 3.314 1.295 4.644l5.727 9.913c.36.647 1.083.971 1.766.971s1.371-.324 1.766-.971l5.727-9.907c.76-1.33 1.295-2.92 1.295-4.644A8.782 8.782 0 0 0 83.803 51zm0 11.384a3.216 3.216 0 0 1-3.208-3.208 3.216 3.216 0 0 1 3.208-3.208 3.216 3.216 0 0 1 3.208 3.208 3.212 3.212 0 0 1-3.208 3.208z" fill="#34A853"/></g><g transform="translate(325 51)"><mask id="k" fill="#fff"><use xlink:href="#j"/></mask><use fill="#5F6368" xlink:href="#j"/><path d="M3.826 7.693a.376.376 0 1 1 0 0zm.365-.898a.377.377 0 1 0 .533.532.377.377 0 0 0-.533-.532zm.898-.899a.374.374 0 0 0 0 .533.377.377 0 1 0 0-.533zm.898-.898a.374.374 0 0 0 0 .533.377.377 0 1 0 0-.533zm.898-.898a.374.374 0 0 0 0 .533.377.377 0 0 0 .533-.533.374.374 0 0 0-.54 0h.007zm.898-.898a.374.374 0 0 0 0 .533.377.377 0 1 0 0-.533zm.898-.898a.374.374 0 0 0 0 .533.377.377 0 1 0 0-.533zm.898-.898a.374.374 0 0 0 0 .533.377.377 0 1 0 0-.533zm.899-.898a.374.374 0 0 0 0 .533.377.377 0 1 0 0-.533zm.898-.898a.374.374 0 0 0 0 .533.378.378 0 0 0 .63-.364.377.377 0 0 0-.63-.17zm.898-.898a.374.374 0 0 0 0 .532.377.377 0 1 0 0-.533zm.898-.898a.374.374 0 0 0 0 .532.378.378 0 0 0 .63-.364.377.377 0 0 0-.63-.168zM4.754 9.156a.378.378 0 1 0 .535.534.378.378 0 0 0-.535-.534zm.9-.898a.374.374 0 0 0 0 .533.377.377 0 1 0 0-.533zm.898-.898a.374.374 0 0 0 0 .532.377.377 0 1 0 0-.532zm.898-.898a.374.374 0 0 0 0 .532.377.377 0 1 0 0-.532zm.898-.899a.374.374 0 0 0 0 .533.377.377 0 1 0 0-.533zm.898-.898a.374.374 0 0 0 0 .533.377.377 0 0 0 .533-.533.374.374 0 0 0-.537 0h.004zm.899-.898a.374.374 0 0 0 0 .533.377.377 0 1 0 0-.533zm.898-.898a.374.374 0 0 0 0 .533.377.377 0 1 0 0-.533zm.898-.898a.374.374 0 0 0 0 .533.376.376 0 0 0 .524-.529.374.374 0 0 0-.524 0v-.004zm.898-.9a.378.378 0 0 0 .533.535.378.378 0 0 0-.533-.535zm.898-.898a.378.378 0 1 0 .502.565.378.378 0 0 0-.502-.565zm.898-.898a.378.378 0 1 0 .502.565.378.378 0 0 0-.502-.565zM4.556 7.89a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.898-.898a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.898-.898a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.898-.898a.377.377 0 1 0 .533 0 .378.378 0 0 0-.533.002v-.002zm.899-.898a.378.378 0 0 0 .363.63.377.377 0 1 0-.363-.63zm.898-.898a.376.376 0 1 0 0 0zm.898-.898a.378.378 0 1 0 .535.534.378.378 0 0 0-.535-.534zm.898-.898a.378.378 0 1 0 .535.534.378.378 0 0 0-.535-.534zm.898-.898a.378.378 0 1 0 .535.534.378.378 0 0 0-.535-.534zm.898-.899a.378.378 0 1 0 .535.535.378.378 0 0 0-.535-.535zm.9-.898a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.898-.898a.374.374 0 0 0 0 .533.377.377 0 1 0 0-.533zM1.83 6.23a.377.377 0 1 0 .532.533.377.377 0 0 0-.532-.533zm.898-.898a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.898-.898a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.898-.898a.377.377 0 1 0 .533 0 .374.374 0 0 0-.542 0h.009zm.898-.898a.376.376 0 1 0 .533.53.376.376 0 0 0-.533-.53zm.898-.898a.374.374 0 0 0 0 .533.378.378 0 0 0 .63-.364.377.377 0 0 0-.63-.169zm.898-.898a.374.374 0 0 0 0 .533.377.377 0 1 0 0-.533zm.898-.898a.374.374 0 0 0 0 .533.378.378 0 0 0 .63-.364.377.377 0 0 0-.63-.17zm.898-.898a.374.374 0 0 0 0 .533.377.377 0 1 0 0-.533zm.898-.898a.374.374 0 0 0 0 .532.377.377 0 1 0 0-.533zm.899-.899a.377.377 0 1 0 .532.533.377.377 0 0 0-.532-.533zm.898-.898a.38.38 0 1 0 .541 0 .377.377 0 0 0-.533 0h-.008zM3.093 6.427a.378.378 0 0 0 .364.63.377.377 0 1 0-.364-.63zm.898-.898a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.898-.898a.378.378 0 1 0 .535.535.378.378 0 0 0-.535-.535zm.898-.898a.378.378 0 1 0 .535.534.378.378 0 0 0-.535-.534zm.898-.898a.378.378 0 1 0 .535.534.378.378 0 0 0-.535-.534zm.898-.898a.378.378 0 1 0 .535.534.378.378 0 0 0-.535-.534zm.899-.898a.378.378 0 1 0 .535.534.378.378 0 0 0-.535-.534zm.9-.899a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.898-.898a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.896-.898a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.898-.898a.377.377 0 1 0 .002 0h-.002zm.898-.898a.377.377 0 1 0 .002 0h-.002zM6.215 10.619a.378.378 0 1 0 .002 0h-.002zm.898-.898a.378.378 0 1 0 .002 0h-.002zm.898-.898a.378.378 0 1 0 .002 0h-.002zm.898-.898a.378.378 0 1 0 .002 0H8.91zm.898-.898a.378.378 0 1 0 .002 0h-.002zm.9-.9a.378.378 0 1 0 .503.565.378.378 0 0 0-.503-.566zm.899-.899a.378.378 0 0 0 .532.535.378.378 0 0 0-.532-.535zm.898-.898a.378.378 0 1 0 .563.505.378.378 0 0 0-.563-.505zm.898-.898a.378.378 0 0 0 .533.535.378.378 0 0 0-.533-.535zm.898-.898a.378.378 0 0 0 .533.535.378.378 0 0 0-.533-.535zm.898-.898a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.898-.898a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zM6.02 9.354a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.898-.899a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.898-.898a.376.376 0 1 0 0 0zm.899-.898a.376.376 0 1 0 0 0zm.898-.898a.376.376 0 1 0 0 0zm.898-.898a.376.376 0 1 0 0 0zm.898-.898a.376.376 0 1 0 0 0zm.898-.898a.376.376 0 1 0 0 0zm.898-.898a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.898-.898a.377.377 0 1 0 .533.532.377.377 0 0 0-.533-.532zM15 .372a.378.378 0 1 0 .535.535A.378.378 0 0 0 15 .372zm.898-.898a.378.378 0 1 0 .535 0 .378.378 0 0 0-.53 0h-.005zm-8.218 12.6a.377.377 0 1 0 .533.532.377.377 0 0 0-.533-.532zm.898-.9a.378.378 0 0 0 .533.534.378.378 0 0 0-.533-.535zm.898-.899a.378.378 0 0 0 .533.535.378.378 0 0 0-.533-.535zm.898-.898a.378.378 0 1 0 .503.565.378.378 0 0 0-.503-.565zm.899-.898a.378.378 0 1 0 .535 0 .38.38 0 0 0-.535.009v-.009zm.898-.898a.378.378 0 1 0 .535 0 .38.38 0 0 0-.535.009v-.01zm.898-.898a.378.378 0 1 0 .535 0 .378.378 0 0 0-.535.02v-.02zm.898-.898a.378.378 0 1 0 .535 0 .378.378 0 0 0-.533.008l-.002-.008zm.9-.898a.377.377 0 1 0 .533.532.377.377 0 0 0-.533-.532zm.898-.898a.377.377 0 1 0 .533.532.377.377 0 0 0-.533-.532zm.898-.899a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.898-.898a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zM7.482 10.808a.376.376 0 1 0 .533 0 .374.374 0 0 0-.533.009v-.009zm.9-.883a.376.376 0 1 0 .534.53.376.376 0 0 0-.533-.53zm.899-.898a.376.376 0 1 0 .533 0 .374.374 0 0 0-.535-.007l.002.007zm.898-.898a.376.376 0 1 0 0 0zm.898-.898a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.898-.898a.377.377 0 1 0 .533.532.377.377 0 0 0-.533-.532zm.898-.898a.377.377 0 1 0 .533.532.377.377 0 0 0-.533-.532zm.898-.899a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.898-.898a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533zm.899-.898a.377.377 0 1 0 .532.533.377.377 0 0 0-.532-.533zm.898-.898a.377.377 0 1 0 .532.533.377.377 0 0 0-.532-.533zm.898-.898a.377.377 0 1 0 .533.533.377.377 0 0 0-.533-.533z" fill="#282A2D" fill-rule="nonzero" mask="url(#k)" transform="rotate(45 9.962 4.478)"/><mask id="n" fill="#fff"><use xlink:href="#l"/></mask><use fill="url(#m)" xlink:href="#l"/><path fill="#000" opacity=".114" mask="url(#n)" d="M-.188-2.663h9.776v33.088H-.188z"/><path fill="url(#o)" mask="url(#n)" d="M3.196 10.121H15.98v2.256H3.196z"/><rect fill="#FBBC05" mask="url(#n)" x="6.58" y="25.913" width="6.016" height="1.504" rx=".752"/><rect fill="#FBBC05" mask="url(#n)" x="8.836" y="16.137" width="1.504" height="10.528" rx=".752"/><circle fill="#FBBC05" mask="url(#n)" cx="9.588" cy="16.513" r="1.88"/></g><path d="M569.1 201.7c38.8-.6 76.3 14 104.4 40.8l77.7-77.7C702 118.6 636.7 93.2 569.1 94c-102.9 0-197 58-243.2 150l90.4 70.1c21.5-64.5 81.8-112.4 152.8-112.4z" fill="#EA4335" fill-rule="nonzero"/></g></svg>
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/images/safe_browsing_banner.svg b/chrome/browser/resources/settings/images/safe_browsing_banner.svg
new file mode 100644
index 0000000..3c1a0a3
--- /dev/null
+++ b/chrome/browser/resources/settings/images/safe_browsing_banner.svg
@@ -0,0 +1 @@
+<svg width="419" height="126" viewBox="0 0 419 126" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient x1="100%" y1="50%" x2="0%" y2="50%" id="a"><stop stop-color="#D6D6D7" offset="0%"/><stop stop-color="#FFF" stop-opacity="0" offset="100%"/></linearGradient><path d="M0 0h193v4a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V0z" id="b"/><path d="M3.375 0h91.25A3.375 3.375 0 0 1 98 3.375v53.25A3.375 3.375 0 0 1 94.625 60H3.375A3.375 3.375 0 0 1 0 56.625V3.375A3.375 3.375 0 0 1 3.375 0z" id="c"/><circle id="e" cx="17" cy="18" r="17"/><path d="M9.975 22c5.516 0 9.582-4.925 9.582-11S16.017.467 10.5.467C4.984.467.557 3.76.557 11c0 7.24 3.901 11 9.418 11z" id="g"/></defs><g fill="none" fill-rule="evenodd"><path fill="url(#a)" transform="rotate(-180 370.809 111.968)" d="M318.309 108.968h105v6h-105z"/><g transform="translate(301 34.558)"><path d="M29 78.442C44.71 70.84 55.426 55.61 57.357 38.145a75.82 75.82 0 0 0 .643-8.45v-17.06L29 .442 0 12.632v17.06a75.82 75.82 0 0 0 .643 8.453C2.573 55.61 13.291 70.84 29 78.442z" stroke="#E8EAED" stroke-width="3" fill="#F8F9FA" fill-rule="nonzero"/><circle fill="#34A853" fill-rule="nonzero" cx="29" cy="35.442" r="19"/><path stroke="#FFF" stroke-width="6.74" d="M19 35.38l6.343 6.062 14.657-14"/></g><g transform="translate(42 14)"><path fill="url(#a)" d="M0 95h105v6H0z"/><path d="M105 1a7 7 0 0 0-7 7v85a7 7 0 0 0 7 7h124a7 7 0 0 0 7-7V8a7 7 0 0 0-7-7H105z" stroke="#E8EAED" stroke-width="2"/><path d="M100 93h47v6h-45a2 2 0 0 1-2-2v-4z" fill="#F8F9FA"/><rect stroke="#E8EAED" stroke-width="2" x="106" y="8" width="122" height="78" rx="1"/><path d="M99 93h47l2 6h-47a2 2 0 0 1-2-2v-4z" fill="#F8F9FA"/><path d="M223 92h66v3a5 5 0 0 1-5 5h-61v-8z" fill="#FFF"/><path stroke="#E8EAED" stroke-width="2" d="M98 92v3a5 5 0 0 0 5 5h181a5 5 0 0 0 5-5v-3H98zM146.32 92.403c0 5.065 2.182 7.597 6.547 7.597"/><path d="M199 91h32v2a3 3 0 0 1-3 3h-26a3 3 0 0 1-3-3v-2z" fill="#E8EAED"/></g><rect stroke="#E8EAED" stroke-width="2" fill-opacity=".2" fill="#34A853" x="148" y="22" width="122" height="78" rx="1"/><g transform="translate(160 31)"><mask id="d" fill="#fff"><use xlink:href="#c"/></mask><use fill="#FFF" fill-rule="nonzero" transform="matrix(1 0 0 -1 0 60)" xlink:href="#c"/><g mask="url(#d)"><g transform="matrix(-1 0 0 1 66 17)"><mask id="f" fill="#fff"><use xlink:href="#e"/></mask><use fill="#8FCBFB" xlink:href="#e"/><path fill="#E8AF48" mask="url(#f)" d="M16 26h5.5v4H16zM9 34.138C9.877 31.379 11.21 30 13 30s3.123.642 4 1.925l-4.824 4.436L9 34.138z"/><path d="M10 34.578c.733-3.892 3.103-5.838 7.11-5.838 4.006 0 7.606.806 10.8 2.417l-10.8 6.857L10 34.578z" fill="#3F85F7" mask="url(#f)"/><path d="M22 35.406C22.287 32.47 23.213 31 24.779 31c1.566 0 2.973.608 4.221 1.824L24.779 38 22 35.406z" fill="#E8AF48" mask="url(#f)"/><g transform="translate(8.057 5)"><mask id="h" fill="#fff"><use xlink:href="#g"/></mask><use fill="#E8AF48" xlink:href="#g"/><path d="M11.073 22c5.247 0 8.87-4.925 8.87-11 0-2.604-.736-2.876-1.566-.927-1.106 2.595-.434 6.547-4.538 9.247-3.197 2.104-3.927 2.03-7.882 1.379C8.94 22.553 9.45 22 11.073 22z" fill="#E2A039" mask="url(#h)"/><path d="M11.542 7.179c1.134 2.31 2.653 3.838 5.823 5.194.075.032.307.13.307-.054s-2.163-1.755-2.52-2.775c2.06 1.02 4.791 1.945 4.791.536 0-5.875-4.715-10.638-10.531-10.638-5.424 0-9.89 4.14-10.468 9.463-.042.386 2.694.639 4.437.639 1.743 0 4.818 0 8.16-2.365z" fill="#414141" mask="url(#h)"/></g><circle fill="#E2A039" cx="28" cy="17" r="2"/><ellipse fill="#454441" cx="12.75" cy="17.5" rx="1" ry="1"/><ellipse fill="#454441" cx="18.25" cy="17.5" rx="1" ry="1"/><path d="M14 22.03c1.39.875 2.714.875 3.969 0" stroke="#EC442B" stroke-width=".8" stroke-linecap="round"/><circle fill="#414141" cx="24" cy="4" r="4"/></g></g><rect fill="#34A853" mask="url(#d)" x="-1.125" width="101.375" height="9" rx="2.25"/><ellipse fill="#572A07" mask="url(#d)" cx="49.5" cy="63.625" rx="5.625" ry="1.125"/><circle fill="#FFF" mask="url(#d)" cx="5.063" cy="5.063" r="1.688"/></g><g transform="translate(52 21)"><path fill="#F1F1F3" fill-rule="nonzero" d="M26.491 65.805l.845-54.408h1.43l.85 54.408z"/><path d="M28.051 49.903a6.346 6.346 0 0 0-6.345-6.35" stroke="#F1F1F3" stroke-width="1.541"/><path d="M20.472 31.485c.763.624.806 1.954 1.411 2.645.605.691 1.959.994 2.4 1.78.48.87.039 2.113.288 2.972.279.984 1.287 1.858 1.195 2.74-.1.985-1.257 1.537-1.857 2.276-.6.74-.922 1.978-1.867 2.266-.85.264-1.92-.557-2.924-.639-.892-.072-2.016.624-2.97.298-.86-.293-1.354-1.526-2.218-2.02-.864-.495-2.108-.24-2.88-.865-.773-.624-.807-1.949-1.412-2.645-.604-.696-1.958-.988-2.4-1.776-.504-.873-.043-2.112-.288-2.97-.278-.99-1.286-1.863-1.195-2.746.096-.984 1.258-1.536 1.858-2.27.6-.735.921-1.978 1.867-2.271.85-.26 1.92.557 2.923.638.893.077 2.016-.624 2.971-.297.86.292 1.354 1.526 2.218 2.02.864.495 2.122.24 2.88.864z" fill="#F1F1F3" fill-rule="nonzero"/><path d="M28.051 49.903a6.35 6.35 0 0 1 6.35-6.35" stroke="#F1F1F3" stroke-width="1.541"/><path d="M35.63 31.485c-.758.624-.801 1.954-1.406 2.645-.605.691-1.958.994-2.4 1.78-.509.87-.043 2.113-.288 2.972-.283.984-1.286 1.858-1.2 2.74.1.985 1.258 1.537 1.862 2.276.605.74.917 1.978 1.868 2.266.844.264 1.92-.557 2.923-.639.888-.072 2.016.624 2.971.298.86-.293 1.354-1.526 2.213-2.02.859-.495 2.112-.24 2.88-.865.768-.624.801-1.949 1.406-2.645.605-.696 1.959-.988 2.4-1.776.509-.873.043-2.112.288-2.97.283-.99 1.291-1.863 1.2-2.746-.1-.984-1.257-1.536-1.862-2.27-.605-.735-.917-1.978-1.867-2.271-.845-.26-1.92.557-2.924.638-.888.077-2.016-.624-2.97-.297-.86.292-1.354 1.526-2.214 2.02-.859.495-2.121.24-2.88.864z" fill="#F1F1F3" fill-rule="nonzero"/><path d="M28.051 30.506a5.117 5.117 0 0 0-5.121-5.121" stroke="#F1F1F3" stroke-width="1.541"/><path d="M21.931 15.645c.615.504.648 1.575 1.138 2.136.49.562 1.584.802 1.949 1.44.408.706.033 1.704.235 2.4.225.797 1.037 1.503.96 2.213-.077.797-1.013 1.243-1.503 1.839-.49.595-.739 1.598-1.507 1.828-.681.212-1.536-.446-2.357-.513-.72-.058-1.632.504-2.4.24-.696-.235-1.094-1.234-1.79-1.632-.696-.399-1.704-.192-2.314-.696-.61-.504-.652-1.58-1.137-2.136-.485-.557-1.584-.802-1.949-1.44-.413-.706-.038-1.71-.235-2.4-.226-.797-1.042-1.503-.96-2.218.077-.792 1.013-1.238 1.502-1.833.49-.596.74-1.599 1.503-1.834.686-.206 1.54.451 2.361.518.72.058 1.632-.48 2.4-.24s1.095 1.234 1.79 1.632c.697.399 1.705.192 2.314.696z" fill="#F1F1F3" fill-rule="nonzero"/><path d="M28.051 30.506a5.122 5.122 0 0 1 5.127-5.121" stroke="#F1F1F3" stroke-width="1.541"/><path d="M34.171 15.645c-.614.504-.648 1.575-1.137 2.136-.49.562-1.58.802-1.95 1.44-.407.706-.033 1.704-.23 2.4-.225.797-1.041 1.503-.96 2.213.082.797 1.018 1.243 1.503 1.839.485.595.744 1.598 1.507 1.828.686.212 1.536-.446 2.362-.513.72-.058 1.627.504 2.4.24.69-.235 1.09-1.234 1.785-1.632.696-.399 1.704-.192 2.319-.696.614-.504.648-1.58 1.137-2.136.49-.557 1.58-.802 1.949-1.44.408-.706.034-1.71.23-2.4.23-.797 1.042-1.503.96-2.218-.081-.792-1.017-1.238-1.502-1.833-.485-.596-.744-1.599-1.507-1.834-.682-.206-1.536.451-2.362.518-.72.058-1.627-.48-2.4-.24-.773.24-1.094 1.234-1.79 1.632-.696.399-1.7.192-2.314.696zM23.194 7.11c0 .644.662 1.215.763 1.81.1.596-.303 1.407-.091 1.964.21.557 1.056.897 1.392 1.377.384.552.417 1.44.902 1.748.485.307 1.3 0 1.92 0 .62 0 1.387.35 1.92 0 .533-.35.48-1.2.883-1.757.331-.48 1.152-.768 1.378-1.387.225-.62-.216-1.32-.11-1.964.105-.643.748-1.176.748-1.819s-.662-1.214-.768-1.81c-.105-.595.307-1.406.096-1.967-.211-.562-1.046-.922-1.382-1.402-.336-.48-.413-1.44-.898-1.747-.485-.307-1.305 0-1.92 0-.614 0-1.387-.35-1.92 0-.533.35-.504 1.2-.883 1.757-.331.48-1.152.768-1.382 1.387-.23.619.22 1.32.115 1.963-.106.643-.768 1.2-.763 1.848z" fill="#F1F1F3" fill-rule="nonzero"/><path d="M46.464 93H9.638a2.821 2.821 0 0 1-2.822-2.586l-2.65-34.395a2.794 2.794 0 0 1 .748-2.118A2.85 2.85 0 0 1 6.989 53h42.125c.788 0 1.54.326 2.076.9.536.572.806 1.34.746 2.12l-2.65 34.394A2.816 2.816 0 0 1 46.464 93z" stroke="#E8EAED" stroke-width="2" fill="#F8F9FA" fill-rule="nonzero"/><rect stroke="#E8EAED" stroke-width="2" fill="#FFF" fill-rule="nonzero" y="50.546" width="56.102" height="8.203" rx="1.781"/></g></g></svg>
\ No newline at end of file
diff --git a/chrome/browser/settings/BUILD.gn b/chrome/browser/settings/BUILD.gn
index 11d74164..e5f8d34 100644
--- a/chrome/browser/settings/BUILD.gn
+++ b/chrome/browser/settings/BUILD.gn
@@ -10,6 +10,7 @@
     "android/java/src/org/chromium/chrome/browser/settings/ManagedPreferencesUtils.java",
     "android/java/src/org/chromium/chrome/browser/settings/SearchUtils.java",
     "android/java/src/org/chromium/chrome/browser/settings/SettingsUtils.java",
+    "android/widget/java/src/org/chromium/chrome/browser/settings/ChromeBasePreference.java",
     "android/widget/java/src/org/chromium/chrome/browser/settings/ChromeImageViewPreference.java",
   ]
   deps = [
diff --git a/chrome/android/java/res/layout/preference_compat.xml b/chrome/browser/settings/android/java/res/layout/preference_compat.xml
similarity index 100%
rename from chrome/android/java/res/layout/preference_compat.xml
rename to chrome/browser/settings/android/java/res/layout/preference_compat.xml
diff --git a/chrome/browser/settings/android/java/res/values-v21/styles.xml b/chrome/browser/settings/android/java/res/values-v21/styles.xml
new file mode 100644
index 0000000..64e418d7
--- /dev/null
+++ b/chrome/browser/settings/android/java/res/values-v21/styles.xml
@@ -0,0 +1,31 @@
+<?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. -->
+
+<resources>
+    <style name="PreferenceLayoutCompat">
+        <item name="android:paddingStart">?android:attr/listPreferredItemPaddingStart</item>
+        <item name="android:paddingEnd">?android:attr/listPreferredItemPaddingEnd</item>
+        <item name="android:minHeight">?android:attr/listPreferredItemHeightSmall</item>
+    </style>
+
+    <style name="PreferenceDescriptionCompat">
+        <item name="android:paddingTop">16dp</item>
+        <item name="android:paddingBottom">16dp</item>
+    </style>
+
+    <style name="PreferenceWidgetCompat">
+        <item name="android:paddingStart">16dp</item>
+    </style>
+
+    <style name="PreferenceTitle">
+        <item name="android:ellipsize">end</item>
+        <item name="android:singleLine">true</item>
+        <item name="android:textAppearance">?android:attr/textAppearanceListItem</item>
+    </style>
+
+    <style name="PreferenceSummary">
+        <item name="android:textAppearance">@style/TextAppearance.BlackBody</item>
+    </style>
+</resources>
diff --git a/chrome/browser/settings/android/java/res/values/attrs.xml b/chrome/browser/settings/android/java/res/values/attrs.xml
new file mode 100644
index 0000000..0eccb76
--- /dev/null
+++ b/chrome/browser/settings/android/java/res/values/attrs.xml
@@ -0,0 +1,11 @@
+<?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. -->
+
+<resources>
+    <declare-styleable name="ChromeBasePreference">
+        <!-- The tint color for the icon set by android:icon. -->
+        <attr name="iconTint" format="color" />
+    </declare-styleable>
+</resources>
diff --git a/chrome/browser/settings/android/java/res/values/styles.xml b/chrome/browser/settings/android/java/res/values/styles.xml
new file mode 100644
index 0000000..91dca86
--- /dev/null
+++ b/chrome/browser/settings/android/java/res/values/styles.xml
@@ -0,0 +1,41 @@
+<?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. -->
+
+<resources>
+    <!-- TODO(crbug.com/971791): The asymmetric start and end paddings here preserve the same
+         overall padding as the pre-support library custom preference layout. Following migration to
+         the support library preferences, we should investigate simplifying these styles.-->
+    <style name="PreferenceLayoutCompat">
+        <item name="android:paddingStart">8dp</item>
+        <item name="android:paddingEnd">10dp</item>
+        <item name="android:minHeight">?android:attr/listPreferredItemHeight</item>
+        <item name="android:background">?android:attr/selectableItemBackground</item>
+    </style>
+
+    <style name="PreferenceDescriptionCompat">
+        <item name="android:paddingTop">6dp</item>
+        <item name="android:paddingBottom">6dp</item>
+        <item name="android:paddingEnd">8dp</item>
+    </style>
+
+    <style name="PreferenceWidgetCompat">
+        <item name="android:minWidth">48dp</item>
+    </style>
+
+    <style name="PreferenceTitle">
+        <item name="android:ellipsize">end</item>
+        <item name="android:singleLine">true</item>
+        <item name="android:textAppearance">@style/TextAppearance.PreferenceMediumText</item>
+    </style>
+
+    <style name="PreferenceSummary">
+        <item name="android:textAppearance">@style/TextAppearance.BlackBody</item>
+    </style>
+
+    <style name="TextAppearance.PreferenceMediumText">
+        <item name="android:textSize">18sp</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    </style>
+</resources>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/ChromeBasePreference.java b/chrome/browser/settings/android/widget/java/src/org/chromium/chrome/browser/settings/ChromeBasePreference.java
similarity index 98%
rename from chrome/android/java/src/org/chromium/chrome/browser/settings/ChromeBasePreference.java
rename to chrome/browser/settings/android/widget/java/src/org/chromium/chrome/browser/settings/ChromeBasePreference.java
index dc00f388..9136673 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/ChromeBasePreference.java
+++ b/chrome/browser/settings/android/widget/java/src/org/chromium/chrome/browser/settings/ChromeBasePreference.java
@@ -15,8 +15,6 @@
 
 import androidx.annotation.Nullable;
 
-import org.chromium.chrome.R;
-
 /**
  * A preference that supports some Chrome-specific customizations:
  *
diff --git a/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.cc b/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.cc
index 2297e66..88ddc73 100644
--- a/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.cc
+++ b/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.cc
@@ -139,6 +139,7 @@
   app_service_controller_->app_service_instance_helper()->OnInstances(
       task_id_to_arc_app_window_info_[task_id]->app_shelf_id().ToString(),
       window, std::string(), state);
+  arc_window_candidates_.erase(window);
 }
 
 void AppServiceAppWindowArcTracker::OnTaskDescriptionUpdated(
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.cc b/chrome/browser/ui/extensions/extension_action_view_controller.cc
index 362af42c9..da9fc13 100644
--- a/chrome/browser/ui/extensions/extension_action_view_controller.cc
+++ b/chrome/browser/ui/extensions/extension_action_view_controller.cc
@@ -404,7 +404,8 @@
   popup_host_observer_.Add(popup_host_);
   extensions_container_->SetPopupOwner(this);
 
-  if (!extensions_container_->IsActionVisibleOnToolbar(this)) {
+  if (!extensions_container_->IsActionVisibleOnToolbar(this) ||
+      base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu)) {
     extensions_container_->CloseOverflowMenuIfOpen();
     extensions_container_->PopOutAction(
         this, show_action == SHOW_POPUP_AND_INSPECT,
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
index d65572b..37082e4 100644
--- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/bind.h"
+#include "base/feature_list.h"
 #include "base/run_loop.h"
 #include "base/scoped_observer.h"
 #include "base/stl_util.h"
@@ -1315,6 +1316,11 @@
 #if !defined(OS_MACOSX)
 // Mac intentionally does not support this behavior.
 IN_PROC_BROWSER_TEST_F(OmniboxViewTest, WrappingTabTraverseResultsTest) {
+  if (base::FeatureList::IsEnabled(
+          omnibox::kOmniboxSuggestionTransparencyOptions)) {
+    return;
+  }
+
   OmniboxView* omnibox_view = nullptr;
   ASSERT_NO_FATAL_FAILURE(GetOmniboxView(&omnibox_view));
   OmniboxPopupModel* popup_model = omnibox_view->model()->popup_model();
diff --git a/chrome/browser/ui/search/instant_theme_browsertest.cc b/chrome/browser/ui/search/instant_theme_browsertest.cc
index 094cd166..9390d34 100644
--- a/chrome/browser/ui/search/instant_theme_browsertest.cc
+++ b/chrome/browser/ui/search/instant_theme_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/feature_list.h"
 #include "base/macros.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
@@ -9,6 +10,7 @@
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/search/instant_service_observer.h"
+#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/browser.h"
@@ -217,6 +219,10 @@
 }
 
 IN_PROC_BROWSER_TEST_F(InstantThemeTest, ThemeAppliedToNewTab) {
+  if (base::FeatureList::IsEnabled(ntp_features::kRealboxMatchOmniboxTheme)) {
+    return;
+  }
+
   // On the existing tab.
   ASSERT_EQ(1, browser()->tab_strip_model()->count());
   ASSERT_EQ(0, browser()->tab_strip_model()->active_index());
diff --git a/chrome/browser/ui/search/local_ntp_doodle_browsertest.cc b/chrome/browser/ui/search/local_ntp_doodle_browsertest.cc
index 22d20bb4..4fb527f9 100644
--- a/chrome/browser/ui/search/local_ntp_doodle_browsertest.cc
+++ b/chrome/browser/ui/search/local_ntp_doodle_browsertest.cc
@@ -16,6 +16,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
+#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search_provider_logos/logo_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/search/instant_test_utils.h"
@@ -48,7 +49,8 @@
 
 const char kCachedB64[] = "\161\247\041\171\337\276";  // b64decode("cached++")
 const char kFreshB64[] = "abc";                        // b64decode("YWJj")
-const int kFakeboxTopPx = 56 + 200 + 38;  // top margin + height + bottom margin
+const int kSearchboxTopPx =
+    56 + 200 + 38;  // top margin + height + bottom margin
 
 #if defined(OS_WIN) || defined(OS_MACOSX)
 const char kFreshDarkB64[] = "xyz";  // b64decode("eHl6");
@@ -113,6 +115,10 @@
         LogoServiceFactory::GetForProfile(browser()->profile()));
   }
 
+  std::string searchbox() {
+    return ntp_features::IsRealboxEnabled() ? "realbox" : "fakebox";
+  }
+
   base::Optional<int> GetDimension(content::WebContents* tab,
                                    const std::string& id,
                                    const std::string& dimension) {
@@ -352,7 +358,8 @@
   base::HistogramTester histograms;
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-default"), Eq(1.0));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-doodle"), Eq(0.0));
 
@@ -376,7 +383,8 @@
   base::HistogramTester histograms;
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-default"), Eq(1.0));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-doodle"), Eq(0.0));
 
@@ -405,7 +413,8 @@
   base::HistogramTester histograms;
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-default"), Eq(0.0));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-doodle"), Eq(1.0));
   EXPECT_THAT(GetComputedDisplay(active_tab, "logo-doodle-container"),
@@ -448,7 +457,8 @@
   base::HistogramTester histograms;
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-default"), Eq(0.0));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-doodle"), Eq(1.0));
   EXPECT_THAT(GetComputedDisplay(active_tab, "logo-doodle-container"),
@@ -484,7 +494,8 @@
   base::HistogramTester histograms;
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-default"), Eq(0.0));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-doodle"), Eq(1.0));
   EXPECT_THAT(GetComputedDisplay(active_tab, "logo-doodle-container"),
@@ -521,7 +532,8 @@
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
   WaitForFadeIn(active_tab, "logo-default");
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-default"), Eq(1.0));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-doodle"), Eq(0.0));
 
@@ -558,7 +570,8 @@
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
   WaitForFadeIn(active_tab, "logo-doodle");
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-default"), Eq(0.0));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-doodle"), Eq(1.0));
   EXPECT_THAT(GetComputedDisplay(active_tab, "logo-doodle-container"),
@@ -605,7 +618,8 @@
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
   WaitForFadeIn(active_tab, "logo-doodle");
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-default"), Eq(0.0));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-doodle"), Eq(1.0));
   EXPECT_THAT(GetComputedDisplay(active_tab, "logo-doodle-container"),
@@ -640,7 +654,8 @@
       local_ntp_test_utils::OpenNewTab(browser(), GURL("about:blank"));
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-default"), Eq(0.0));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-doodle"), Eq(1.0));
   EXPECT_THAT(GetComputedDisplay(active_tab, "logo-doodle-container"),
@@ -680,7 +695,8 @@
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
   WaitForFadeIn(active_tab, "logo-doodle");
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-default"), Eq(0.0));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-doodle"), Eq(1.0));
   EXPECT_THAT(GetComputedDisplay(active_tab, "logo-doodle-container"),
@@ -734,7 +750,8 @@
   base::HistogramTester histograms;
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-default"), Eq(0.0));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-doodle"), Eq(1.0));
   EXPECT_THAT(GetComputedDisplay(active_tab, "logo-doodle-container"),
@@ -1147,7 +1164,8 @@
   base::HistogramTester histograms;
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-default"), Eq(0.0));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-doodle"), Eq(1.0));
   EXPECT_THAT(GetComputedDisplay(active_tab, "logo-doodle-container"),
@@ -1164,7 +1182,8 @@
   ASSERT_TRUE(content::ExecuteScript(
       active_tab, "document.getElementById('logo-doodle-button').click();"));
 
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetElementProperty(active_tab, "logo-doodle-image", "src"),
               Eq(cached_logo.metadata.animated_url.spec()));
   // TODO(sfiera): check href by clicking on button.
@@ -1365,7 +1384,8 @@
     base::HistogramTester histograms;
     ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
-    EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx))
+    EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+                Eq(kSearchboxTopPx))
         << "iframe_height_px = " << height;
   }
 }
@@ -1393,7 +1413,8 @@
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
   // Initial dimensions are correct:
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetDimension(active_tab, "logo-doodle-iframe", "width"), Eq(400));
   EXPECT_THAT(GetDimension(active_tab, "logo-doodle-iframe", "height"),
               Eq(220));
@@ -1413,8 +1434,8 @@
                                      )js"));
 
   // Fakebox is now 180px lower, with the iframe larger, as requested.
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"),
-              Eq(kFakeboxTopPx + 180));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx + 180));
   EXPECT_THAT(GetDimension(active_tab, "logo-doodle-iframe", "width"),
               Eq(GetDimension(active_tab, "logo", "width")));
   EXPECT_THAT(GetDimension(active_tab, "logo-doodle-iframe", "height"),
@@ -1431,7 +1452,8 @@
                                      )js"));
 
   // Back to the original dimensions now.
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetDimension(active_tab, "logo-doodle-iframe", "width"), Eq(400));
   EXPECT_THAT(GetDimension(active_tab, "logo-doodle-iframe", "height"),
               Eq(220));
@@ -1488,7 +1510,8 @@
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
   WaitForFadeIn(active_tab, "logo-doodle");
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-default"), Eq(0.0));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-doodle"), Eq(1.0));
   EXPECT_THAT(GetComputedDisplay(active_tab, "logo-doodle-container"),
@@ -1546,7 +1569,8 @@
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
   WaitForFadeIn(active_tab, "logo-doodle");
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-default"), Eq(0.0));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-doodle"), Eq(1.0));
   EXPECT_THAT(GetComputedDisplay(active_tab, "logo-doodle-container"),
@@ -1579,7 +1603,8 @@
 
   WaitForLogoSwap(active_tab, "logo-doodle");
   EXPECT_TRUE(GetIsDarkModeApplied(active_tab));
-  EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx));
+  EXPECT_THAT(GetDimension(active_tab, searchbox(), "top"),
+              Eq(kSearchboxTopPx));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-default"), Eq(0.0));
   EXPECT_THAT(GetComputedOpacity(active_tab, "logo-doodle"), Eq(1.0));
   EXPECT_THAT(GetComputedDisplay(active_tab, "logo-doodle-container"),
diff --git a/chrome/browser/ui/search/local_ntp_uitest.cc b/chrome/browser/ui/search/local_ntp_uitest.cc
index ad857a9..89478ac 100644
--- a/chrome/browser/ui/search/local_ntp_uitest.cc
+++ b/chrome/browser/ui/search/local_ntp_uitest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -32,6 +33,9 @@
 };
 
 IN_PROC_BROWSER_TEST_F(LocalNtpUiTest, FakeboxRedirectsToOmnibox) {
+  if (ntp_features::IsRealboxEnabled())
+    return;
+
   content::WebContents* active_tab =
       local_ntp_test_utils::OpenNewTab(browser(), GURL("about:blank"));
   local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser(), 1000);
diff --git a/chrome/browser/ui/search/local_ntp_voice_search_browsertest.cc b/chrome/browser/ui/search/local_ntp_voice_search_browsertest.cc
index 3f3ff0c..cc1d3c75 100644
--- a/chrome/browser/ui/search/local_ntp_voice_search_browsertest.cc
+++ b/chrome/browser/ui/search/local_ntp_voice_search_browsertest.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/permissions/permission_manager_factory.h"
 #include "chrome/browser/permissions/permission_request_manager.h"
 #include "chrome/browser/permissions/permission_result.h"
+#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
 #include "chrome/browser/ui/browser.h"
@@ -27,6 +28,11 @@
  public:
   LocalNTPVoiceSearchSmokeTest() {}
 
+  std::string searchbox_microphone() {
+    return ntp_features::IsRealboxEnabled() ? "realbox-microphone"
+                                            : "fakebox-microphone";
+  }
+
  private:
   void SetUpCommandLine(base::CommandLine* cmdline) override {
     // Requesting microphone permission doesn't work unless there's a device
@@ -53,13 +59,15 @@
             active_tab->GetController().GetVisibleEntry()->GetURL());
 
   // Make sure the microphone icon in the fakebox is present and visible.
-  bool fakebox_microphone_is_visible = false;
+  bool microphone_is_visible = false;
   ASSERT_TRUE(instant_test_utils::GetBoolFromJS(
       active_tab,
-      "!!document.getElementById('fakebox-microphone') && "
-      "!document.getElementById('fakebox-microphone').hidden",
-      &fakebox_microphone_is_visible));
-  EXPECT_TRUE(fakebox_microphone_is_visible);
+      "!!document.getElementById('" + searchbox_microphone() +
+          "') && "
+          "!document.getElementById('" +
+          searchbox_microphone() + "').hidden",
+      &microphone_is_visible));
+  EXPECT_TRUE(microphone_is_visible);
 
   // We shouldn't have gotten any console error messages.
   EXPECT_TRUE(console_observer.message().empty()) << console_observer.message();
@@ -95,7 +103,8 @@
 
   // Click on the microphone button, which will trigger a permission request.
   ASSERT_TRUE(content::ExecuteScript(
-      active_tab, "document.getElementById('fakebox-microphone').click();"));
+      active_tab,
+      "document.getElementById('" + searchbox_microphone() + "').click();"));
 
   // Make sure the request arrived.
   prompt_factory.WaitForPermissionBubble();
diff --git a/chrome/browser/ui/views/download/download_item_view.cc b/chrome/browser/ui/views/download/download_item_view.cc
index b72dfab..ffc2cf5 100644
--- a/chrome/browser/ui/views/download/download_item_view.cc
+++ b/chrome/browser/ui/views/download/download_item_view.cc
@@ -220,7 +220,8 @@
       accessible_alert_(accessible_alert),
       announce_accessible_alert_soon_(false),
       deep_scanning_label_(nullptr),
-      open_now_button_(nullptr) {
+      open_now_button_(nullptr),
+      scan_button_(nullptr) {
   views::InstallRectHighlightPathGenerator(this);
   model_->AddObserver(this);
 
@@ -494,6 +495,8 @@
     }
     if (discard_button_)
       discard_button_->SetBoundsRect(gfx::Rect(child_origin, button_size));
+    if (scan_button_)
+      scan_button_->SetBoundsRect(gfx::Rect(child_origin, button_size));
   } else if (IsShowingDeepScanning()) {
     gfx::Point child_origin(
         kStartPadding + GetWarningIconSize() + kStartPadding,
@@ -711,6 +714,9 @@
     return;
   }
 
+  if (sender == scan_button_)
+    return;
+
   DCHECK_EQ(discard_button_, sender);
   UMA_HISTOGRAM_LONG_TIMES("clickjacking.discard_download", warning_duration);
   MaybeSubmitDownloadToFeedbackService(DownloadCommands::DISCARD);
@@ -910,6 +916,8 @@
     shelf_->ConfigureButtonForTheme(discard_button_);
   if (open_now_button_)
     shelf_->ConfigureButtonForTheme(open_now_button_);
+  if (scan_button_)
+    shelf_->ConfigureButtonForTheme(scan_button_);
 }
 
 void DownloadItemView::ShowContextMenuImpl(const gfx::Rect& rect,
@@ -993,6 +1001,8 @@
   save_button_ = nullptr;
   delete discard_button_;
   discard_button_ = nullptr;
+  delete scan_button_;
+  scan_button_ = nullptr;
   delete dangerous_download_label_;
   dangerous_download_label_ = nullptr;
   dangerous_download_label_sized_ = false;
@@ -1037,6 +1047,13 @@
     discard_button_ = AddChildView(std::move(discard_button));
   }
 
+  if (model_->GetDangerType() ==
+      download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING) {
+    auto scan_button = views::MdTextButton::Create(
+        this, l10n_util::GetStringUTF16(IDS_SCAN_DOWNLOAD));
+    scan_button_ = AddChildView(std::move(scan_button));
+  }
+
   base::string16 dangerous_label =
       model_->GetWarningText(font_list_, kTextWidth);
   auto dangerous_download_label = std::make_unique<views::StyledLabel>(
@@ -1080,10 +1097,17 @@
 
     case download::DOWNLOAD_DANGER_TYPE_ASYNC_SCANNING:
     case download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_WARNING:
-      return gfx::CreateVectorIcon(vector_icons::kErrorIcon, GetErrorIconSize(),
-                                   gfx::kGoogleGrey600);
+      return gfx::CreateVectorIcon(
+          vector_icons::kErrorIcon, GetErrorIconSize(),
+          GetNativeTheme()->GetSystemColor(
+              ui::NativeTheme::kColorId_DefaultIconColor));
 
     case download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING:
+      return gfx::CreateVectorIcon(
+          vector_icons::kHelpIcon, GetWarningIconSize(),
+          GetNativeTheme()->GetSystemColor(
+              ui::NativeTheme::kColorId_DefaultIconColor));
+
     case download::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_SAFE:
     case download::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_OPENED_DANGEROUS:
     case download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
@@ -1105,6 +1129,7 @@
       model_->GetFileNameToReportUser(), font_list_, kTextWidth);
   base::string16 deep_scanning_text = l10n_util::GetStringFUTF16(
       IDS_PROMPT_DEEP_SCANNING_DOWNLOAD, elided_filename);
+
   auto deep_scanning_label = std::make_unique<views::StyledLabel>(
       deep_scanning_text, /*listener=*/nullptr);
   deep_scanning_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
@@ -1161,6 +1186,8 @@
     size.SetToMax(discard_button_->GetPreferredSize());
   if (save_button_)
     size.SetToMax(save_button_->GetPreferredSize());
+  if (scan_button_)
+    size.SetToMax(scan_button_->GetPreferredSize());
   return size;
 }
 
diff --git a/chrome/browser/ui/views/download/download_item_view.h b/chrome/browser/ui/views/download/download_item_view.h
index 0f73102..7e3cd4e 100644
--- a/chrome/browser/ui/views/download/download_item_view.h
+++ b/chrome/browser/ui/views/download/download_item_view.h
@@ -427,6 +427,9 @@
   // Icon for the download.
   gfx::ImageSkia icon_;
 
+  // Button used to consent to deep scanning.
+  views::MdTextButton* scan_button_ = nullptr;
+
   // Method factory used to delay reenabling of the item when opening the
   // downloaded file.
   base::WeakPtrFactory<DownloadItemView> weak_ptr_factory_{this};
diff --git a/chrome/browser/ui/views/download/download_shelf_context_menu_view.cc b/chrome/browser/ui/views/download/download_shelf_context_menu_view.cc
index 4afa4e86..02d384e 100644
--- a/chrome/browser/ui/views/download/download_shelf_context_menu_view.cc
+++ b/chrome/browser/ui/views/download/download_shelf_context_menu_view.cc
@@ -61,7 +61,6 @@
                                                   int event_flags) {
   DownloadCommands::Command command =
       static_cast<DownloadCommands::Command>(command_id);
-  DCHECK_NE(command, DownloadCommands::DISCARD);
 
   if (command == DownloadCommands::KEEP) {
     download_item_view_->MaybeSubmitDownloadToFeedbackService(
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views.cc b/chrome/browser/ui/views/exclusive_access_bubble_views.cc
index 24bded78..bade6d8 100644
--- a/chrome/browser/ui/views/exclusive_access_bubble_views.cc
+++ b/chrome/browser/ui/views/exclusive_access_bubble_views.cc
@@ -141,7 +141,7 @@
 }
 
 void ExclusiveAccessBubbleViews::HideImmediately() {
-  if (!popup_->IsVisible())
+  if (!IsShowing() && !popup_->IsVisible())
     return;
 
   RunHideCallbackIfNeeded(ExclusiveAccessBubbleHideReason::kInterrupted);
@@ -150,6 +150,10 @@
   animation_->Hide();
 }
 
+bool ExclusiveAccessBubbleViews::IsShowing() {
+  return IsAnimating() && animation_->IsShowing();
+}
+
 views::View* ExclusiveAccessBubbleViews::GetView() {
   return view_;
 }
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views.h b/chrome/browser/ui/views/exclusive_access_bubble_views.h
index 694401a..89837f2 100644
--- a/chrome/browser/ui/views/exclusive_access_bubble_views.h
+++ b/chrome/browser/ui/views/exclusive_access_bubble_views.h
@@ -58,8 +58,13 @@
   // itself.
   void HideImmediately();
 
+  // Returns true if the popup is being shown (and not fully shown).
+  bool IsShowing();
+
   views::View* GetView();
 
+  gfx::SlideAnimation* animation_for_test() { return animation_.get(); }
+
  private:
   // Starts or stops polling the mouse location based on |popup_| and
   // |bubble_type_|.
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
index b215a66..98f7fb5 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
@@ -288,7 +288,7 @@
   ShowUi("");
   VerifyUi();
 
-  ExtensionsContainer* const extensions_container =
+  ExtensionsToolbarContainer* const extensions_container =
       BrowserView::GetBrowserViewForBrowser(browser())
           ->toolbar()
           ->extensions_container();
@@ -308,6 +308,12 @@
 
   extensions_container->HideActivePopup();
 
+  // Wait for animations to finish.
+  base::RunLoop loop;
+  extensions_container->animating_layout_manager()->PostOrQueueAction(
+      loop.QuitClosure());
+  loop.Run();
+
   // After dismissing the popup there should no longer be a popped-out action
   // and the icon should no longer be visible in the extensions container.
   EXPECT_EQ(nullptr, extensions_container->GetPoppedOutAction());
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
index c622b674..6743f894 100644
--- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
+++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
@@ -179,6 +179,9 @@
   ToolbarActionViewController* const popped_out_action = popped_out_action_;
   popped_out_action_ = nullptr;
   UpdateIconVisibility(popped_out_action->GetId());
+  GetViewForId(popped_out_action->GetId())
+      ->ClearProperty(views::kFlexBehaviorKey);
+  InvalidateLayout();
 }
 
 void ExtensionsToolbarContainer::SetPopupOwner(
@@ -210,8 +213,9 @@
   // TODO(pbos): Highlight popout differently.
   DCHECK(!popped_out_action_);
   popped_out_action_ = action;
+  GetViewForId(action->GetId())
+      ->SetProperty(views::kFlexBehaviorKey, views::FlexSpecification());
   UpdateIconVisibility(popped_out_action_->GetId());
-  ReorderViews();
   static_cast<views::AnimatingLayoutManager*>(GetLayoutManager())
       ->PostOrQueueAction(closure);
 }
@@ -321,10 +325,6 @@
   if (drop_info_.get())
     ReorderChildView(icons_[drop_info_->action_id].get(), drop_info_->index);
 
-  // Popped out actions should be at the end.
-  if (popped_out_action_)
-    ReorderChildView(icons_[popped_out_action_->GetId()].get(), -1);
-
   // The extension button is always last.
   ReorderChildView(extensions_button_, -1);
 }
diff --git a/chrome/browser/ui/views/frame/webui_tab_strip_container_view.h b/chrome/browser/ui/views/frame/webui_tab_strip_container_view.h
index d58a34d..c3cd1aa 100644
--- a/chrome/browser/ui/views/frame/webui_tab_strip_container_view.h
+++ b/chrome/browser/ui/views/frame/webui_tab_strip_container_view.h
@@ -72,6 +72,8 @@
   // the container's preferred size will change.
   void SetVisibleForTesting(bool visible);
   views::WebView* web_view_for_testing() const { return web_view_; }
+  ToolbarButton* new_tab_button_for_testing() const { return new_tab_button_; }
+  views::View* tab_counter_for_testing() const { return tab_counter_; }
 
  private:
   class AutoCloser;
diff --git a/chrome/browser/ui/views/frame/webui_tab_strip_container_view_unittest.cc b/chrome/browser/ui/views/frame/webui_tab_strip_container_view_unittest.cc
index 920f38360..3eed59c 100644
--- a/chrome/browser/ui/views/frame/webui_tab_strip_container_view_unittest.cc
+++ b/chrome/browser/ui/views/frame/webui_tab_strip_container_view_unittest.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/test_with_browser_view.h"
+#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/common/chrome_switches.h"
 #include "ui/base/test/material_design_controller_test_api.h"
 #include "ui/base/ui_base_switches.h"
@@ -56,6 +57,17 @@
   ASSERT_NE(nullptr, browser_view()->webui_tab_strip());
 }
 
+TEST_F(WebUITabStripContainerViewTest, ButtonsPresentInToolbar) {
+  ASSERT_NE(nullptr,
+            browser_view()->webui_tab_strip()->new_tab_button_for_testing());
+  EXPECT_TRUE(browser_view()->toolbar()->Contains(
+      browser_view()->webui_tab_strip()->new_tab_button_for_testing()));
+  ASSERT_NE(nullptr,
+            browser_view()->webui_tab_strip()->tab_counter_for_testing());
+  EXPECT_TRUE(browser_view()->toolbar()->Contains(
+      browser_view()->webui_tab_strip()->tab_counter_for_testing()));
+}
+
 class WebUITabStripDevToolsTest : public WebUITabStripContainerViewTest {
  public:
   WebUITabStripDevToolsTest()
diff --git a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.cc b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.cc
index e04d1d0..4794abce 100644
--- a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.cc
+++ b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.cc
@@ -175,7 +175,14 @@
       DCHECK_EQ(InputEntryMethod::NOT_ACTIVE, input_entry_method_);
       if (!in_mouse_cooldown_mode_ &&
           event.y() <= kShowFullscreenExitControlHeight) {
-        ShowForInputEntryMethod(InputEntryMethod::MOUSE);
+        // If the exit fullscreen prompt is being shown (say user just pressed
+        // F11 with the cursor on the top of the screen) then we suppress the
+        // fullscreen control host and just put it in cooldown mode.
+        if (browser_view_->exclusive_access_bubble()->IsShowing()) {
+          in_mouse_cooldown_mode_ = true;
+        } else {
+          ShowForInputEntryMethod(InputEntryMethod::MOUSE);
+        }
       } else if (in_mouse_cooldown_mode_ &&
                  event.y() >= CalculateCursorBufferHeight()) {
         in_mouse_cooldown_mode_ = false;
diff --git a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view_interactive_uitest.cc b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view_interactive_uitest.cc
index dca7ea2..b1d4a25 100644
--- a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view_interactive_uitest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller_test.h"
+#include "chrome/browser/ui/views/exclusive_access_bubble_views.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.h"
 #include "chrome/browser/ui/views/fullscreen_control/fullscreen_control_view.h"
@@ -30,6 +31,7 @@
 #include "ui/events/base_event_utils.h"
 #include "ui/events/event.h"
 #include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/gfx/animation/animation_test_api.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/view.h"
 #include "url/gurl.h"
@@ -95,6 +97,12 @@
     return browser()->exclusive_access_manager();
   }
 
+  ExclusiveAccessBubbleViews* GetExclusiveAccessBubble() {
+    BrowserView* browser_view =
+        BrowserView::GetBrowserViewForBrowser(browser());
+    return browser_view->exclusive_access_bubble();
+  }
+
   KeyboardLockController* GetKeyboardLockController() {
     return GetExclusiveAccessManager()->keyboard_lock_controller();
   }
@@ -116,6 +124,19 @@
     ASSERT_TRUE(delegate->IsFullscreenForTabOrPending(GetActiveWebContents()));
   }
 
+  void EnterActiveTabFullscreenAndFinishPromptAnimation() {
+    EnterActiveTabFullscreen();
+    FinishPromptAnimation();
+  }
+
+  void FinishPromptAnimation() {
+    gfx::AnimationTestApi animation_api(
+        GetExclusiveAccessBubble()->animation_for_test());
+    base::TimeTicks far_future =
+        base::TimeTicks::Now() + base::TimeDelta::FromDays(1);
+    animation_api.Step(far_future);
+  }
+
   bool EnableKeyboardLock() {
     base::Optional<base::flat_set<ui::DomCode>> codes({ui::DomCode::ESCAPE});
     return content::RequestKeyboardLock(GetActiveWebContents(),
@@ -154,7 +175,7 @@
 // immediately created when FullscreenControlHost is created.
 IN_PROC_BROWSER_TEST_F(FullscreenControlViewTest,
                        NoFullscreenPopupOnBrowserFullscreen) {
-  EnterActiveTabFullscreen();
+  EnterActiveTabFullscreenAndFinishPromptAnimation();
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
   DCHECK(browser_view);
   ASSERT_TRUE(browser_view->IsFullscreen());
@@ -167,7 +188,7 @@
 #if !defined(OS_MACOSX)
 
 IN_PROC_BROWSER_TEST_F(FullscreenControlViewTest, MouseExitFullscreen) {
-  EnterActiveTabFullscreen();
+  EnterActiveTabFullscreenAndFinishPromptAnimation();
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
   ASSERT_TRUE(browser_view->IsFullscreen());
 
@@ -196,7 +217,7 @@
 
 IN_PROC_BROWSER_TEST_F(FullscreenControlViewTest,
                        MouseExitFullscreen_TimeoutAndRetrigger) {
-  EnterActiveTabFullscreen();
+  EnterActiveTabFullscreenAndFinishPromptAnimation();
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
   ASSERT_TRUE(browser_view->IsFullscreen());
 
@@ -248,7 +269,9 @@
   ASSERT_TRUE(browser_view->IsFullscreen());
 }
 
-IN_PROC_BROWSER_TEST_F(FullscreenControlViewTest, TouchPopupInteraction) {
+IN_PROC_BROWSER_TEST_F(
+    FullscreenControlViewTest,
+    MouseOnTopWhenPromptIsShowing_ButtonNotShownUntilMouseLeavesBufferArea) {
   EnterActiveTabFullscreen();
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
   ASSERT_TRUE(browser_view->IsFullscreen());
@@ -257,6 +280,49 @@
   host->Hide(false);
   ASSERT_FALSE(host->IsVisible());
 
+  // Simulate moving the mouse to the top of the screen, which will not trigger
+  // the fullscreen exit UI yet since the prompt is still showing.
+  ui::MouseEvent mouse_move(ui::ET_MOUSE_MOVED, gfx::Point(1, 1), gfx::Point(),
+                            base::TimeTicks(), 0, 0);
+  host->OnMouseEvent(mouse_move);
+  ASSERT_FALSE(host->IsVisible());
+
+  // This still doesn't trigger the UI since the prompt is still showing.
+  mouse_move = ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(2, 1),
+                              gfx::Point(), base::TimeTicks(), 0, 0);
+  host->OnMouseEvent(mouse_move);
+  ASSERT_FALSE(host->IsVisible());
+
+  FinishPromptAnimation();
+
+  // This still doesn't trigger the UI since it's in cooldown mode.
+  mouse_move = ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(3, 1),
+                              gfx::Point(), base::TimeTicks(), 0, 0);
+  host->OnMouseEvent(mouse_move);
+  ASSERT_FALSE(host->IsVisible());
+
+  // Move the cursor out of the buffer area, which will have no effect.
+  mouse_move = ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(2, 1000),
+                              gfx::Point(), base::TimeTicks(), 0, 0);
+  host->OnMouseEvent(mouse_move);
+  ASSERT_FALSE(host->IsVisible());
+
+  // The UI should be triggered now.
+  mouse_move = ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(1, 1),
+                              gfx::Point(), base::TimeTicks(), 0, 0);
+  host->OnMouseEvent(mouse_move);
+  ASSERT_TRUE(host->IsVisible());
+}
+
+IN_PROC_BROWSER_TEST_F(FullscreenControlViewTest, TouchPopupInteraction) {
+  EnterActiveTabFullscreenAndFinishPromptAnimation();
+  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
+  ASSERT_TRUE(browser_view->IsFullscreen());
+
+  FullscreenControlHost* host = GetFullscreenControlHost();
+  host->Hide(false);
+  ASSERT_FALSE(host->IsVisible());
+
   // Simulate a short tap that doesn't trigger the popup.
   ui::TouchEvent touch_event(
       ui::ET_TOUCH_PRESSED, gfx::Point(1, 1), ui::EventTimeForNow(),
@@ -329,7 +395,7 @@
 
 IN_PROC_BROWSER_TEST_F(FullscreenControlViewTest,
                        MouseAndTouchInteraction_NoInterference) {
-  EnterActiveTabFullscreen();
+  EnterActiveTabFullscreenAndFinishPromptAnimation();
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
   ASSERT_TRUE(browser_view->IsFullscreen());
 
@@ -404,7 +470,7 @@
 #endif
 
 IN_PROC_BROWSER_TEST_F(FullscreenControlViewTest, KeyboardPopupInteraction) {
-  EnterActiveTabFullscreen();
+  EnterActiveTabFullscreenAndFinishPromptAnimation();
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
   ASSERT_TRUE(browser_view->IsFullscreen());
 
diff --git a/chrome/browser/ui/views/passwords/password_pending_view.cc b/chrome/browser/ui/views/passwords/password_pending_view.cc
index 3389f29f..93c22d2 100644
--- a/chrome/browser/ui/views/passwords/password_pending_view.cc
+++ b/chrome/browser/ui/views/passwords/password_pending_view.cc
@@ -361,6 +361,7 @@
   if (is_update_state_before != model()->IsCurrentStateUpdate() ||
       is_ok_button_enabled_before !=
           IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK)) {
+    UpdateDialogButtons();
     DialogModelChanged();
     // TODO(ellyjones): This should not be necessary; DialogModelChanged()
     // implies a re-layout of the dialog.
@@ -387,28 +388,6 @@
   return (initial_view && initial_view->IsFocusable()) ? initial_view : nullptr;
 }
 
-int PasswordPendingView::GetDialogButtons() const {
-  if (sign_in_promo_)
-    return ui::DIALOG_BUTTON_NONE;
-
-  return PasswordBubbleViewBase::GetDialogButtons();
-}
-
-base::string16 PasswordPendingView::GetDialogButtonLabel(
-    ui::DialogButton button) const {
-  int message = 0;
-  if (button == ui::DIALOG_BUTTON_OK) {
-    message = model()->IsCurrentStateUpdate()
-                  ? IDS_PASSWORD_MANAGER_UPDATE_BUTTON
-                  : IDS_PASSWORD_MANAGER_SAVE_BUTTON;
-  } else {
-    message = is_update_bubble_ ? IDS_PASSWORD_MANAGER_CANCEL_BUTTON
-                                : IDS_PASSWORD_MANAGER_BUBBLE_BLACKLIST_BUTTON;
-  }
-
-  return l10n_util::GetStringUTF16(message);
-}
-
 bool PasswordPendingView::IsDialogButtonEnabled(ui::DialogButton button) const {
   return button != ui::DIALOG_BUTTON_OK ||
          model()->pending_password().IsFederatedCredential() ||
@@ -485,12 +464,29 @@
   }
   GetWidget()->UpdateWindowIcon();
   GetWidget()->UpdateWindowTitle();
+  UpdateDialogButtons();
   DialogModelChanged();
 
   SizeToContents();
 #endif  // defined(OS_CHROMEOS)
 }
 
+void PasswordPendingView::UpdateDialogButtons() {
+  DialogDelegate::set_buttons(
+      sign_in_promo_ ? ui::DIALOG_BUTTON_NONE
+                     : (ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL));
+  DialogDelegate::set_button_label(
+      ui::DIALOG_BUTTON_OK,
+      l10n_util::GetStringUTF16(model()->IsCurrentStateUpdate()
+                                    ? IDS_PASSWORD_MANAGER_UPDATE_BUTTON
+                                    : IDS_PASSWORD_MANAGER_SAVE_BUTTON));
+  DialogDelegate::set_button_label(
+      ui::DIALOG_BUTTON_CANCEL,
+      l10n_util::GetStringUTF16(
+          is_update_bubble_ ? IDS_PASSWORD_MANAGER_CANCEL_BUTTON
+                            : IDS_PASSWORD_MANAGER_BUBBLE_BLACKLIST_BUTTON));
+}
+
 std::unique_ptr<views::View> PasswordPendingView::CreateFooterView() {
   if (!model()->ShouldShowFooter())
     return nullptr;
diff --git a/chrome/browser/ui/views/passwords/password_pending_view.h b/chrome/browser/ui/views/passwords/password_pending_view.h
index 2a1f80f..a8ea4570 100644
--- a/chrome/browser/ui/views/passwords/password_pending_view.h
+++ b/chrome/browser/ui/views/passwords/password_pending_view.h
@@ -47,8 +47,6 @@
   // PasswordBubbleViewBase:
   gfx::Size CalculatePreferredSize() const override;
   views::View* GetInitiallyFocusedView() override;
-  int GetDialogButtons() const override;
-  base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   bool IsDialogButtonEnabled(ui::DialogButton button) const override;
   gfx::ImageSkia GetWindowIcon() override;
   bool ShouldShowWindowIcon() const override;
@@ -64,6 +62,7 @@
   void TogglePasswordVisibility();
   void UpdateUsernameAndPasswordInModel();
   void ReplaceWithPromo();
+  void UpdateDialogButtons();
   std::unique_ptr<views::View> CreateFooterView();
 
   // True iff it is an update password bubble on creation. False iff it is a
diff --git a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc
index c52f8727..b168514c 100644
--- a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc
+++ b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc
@@ -38,14 +38,6 @@
 #include "ui/views/layout/layout_types.h"
 #include "ui/views/view_class_properties.h"
 
-namespace {
-
-constexpr int TAB_GROUP_HEADER_CXMENU_NEW_TAB_IN_GROUP = 13;
-constexpr int TAB_GROUP_HEADER_CXMENU_UNGROUP = 14;
-constexpr int TAB_GROUP_HEADER_CXMENU_CLOSE_GROUP = 15;
-constexpr int TAB_GROUP_HEADER_CXMENU_FEEDBACK = 16;
-}  // namespace
-
 // static
 views::Widget* TabGroupEditorBubbleView::Show(
     TabGroupHeader* anchor_view,
diff --git a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.h b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.h
index 3bcbf802..d28fcd6 100644
--- a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.h
+++ b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.h
@@ -29,6 +29,11 @@
 // A dialog for changing a tab group's visual parameters.
 class TabGroupEditorBubbleView : public views::BubbleDialogDelegateView {
  public:
+  static constexpr int TAB_GROUP_HEADER_CXMENU_NEW_TAB_IN_GROUP = 13;
+  static constexpr int TAB_GROUP_HEADER_CXMENU_UNGROUP = 14;
+  static constexpr int TAB_GROUP_HEADER_CXMENU_CLOSE_GROUP = 15;
+  static constexpr int TAB_GROUP_HEADER_CXMENU_FEEDBACK = 16;
+
   // Shows the editor for |group|. Returns an *unowned* pointer to the
   // bubble's widget.
   static views::Widget* Show(TabGroupHeader* anchor_view,
diff --git a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view_browsertest.cc b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view_browsertest.cc
index c0788c97..f98617e 100644
--- a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view_browsertest.cc
@@ -5,6 +5,8 @@
 #include "chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.h"
 
 #include "base/time/time.h"
+#include "chrome/browser/ui/tabs/tab_group.h"
+#include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/tabs/tab_group_header.h"
@@ -13,6 +15,7 @@
 #include "components/tab_groups/tab_group_id.h"
 #include "ui/events/event.h"
 #include "ui/gfx/geometry/point_f.h"
+#include "ui/views/test/button_test_api.h"
 
 class TabGroupEditorBubbleViewDialogBrowserTest : public DialogBrowserTest {
  protected:
@@ -21,17 +24,27 @@
         browser()->tab_strip_model()->AddToNewGroup({0});
 
     BrowserView* browser_view = static_cast<BrowserView*>(browser()->window());
-    TabGroupHeader* header =
-        browser_view->tabstrip()->group_views_[group]->header();
+    TabGroupHeader* header = browser_view->tabstrip()->group_header(group);
     ASSERT_NE(nullptr, header);
+    ASSERT_FALSE(header->editor_bubble_tracker_.is_open());
 
     ui::MouseEvent pressed_event(ui::ET_MOUSE_PRESSED, gfx::PointF(),
                                  gfx::PointF(), base::TimeTicks(), 0, 0);
     header->OnMousePressed(pressed_event);
 
+    ASSERT_FALSE(header->editor_bubble_tracker_.is_open());
+
     ui::MouseEvent released_event(ui::ET_MOUSE_RELEASED, gfx::PointF(),
                                   gfx::PointF(), base::TimeTicks(), 0, 0);
     header->OnMouseReleased(released_event);
+
+    ASSERT_TRUE(header->editor_bubble_tracker_.is_open());
+  }
+
+  static views::Widget* GetEditorBubbleWidget(const TabGroupHeader* header) {
+    return header->editor_bubble_tracker_.is_open()
+               ? header->editor_bubble_tracker_.widget()
+               : nullptr;
   }
 };
 
@@ -39,3 +52,90 @@
                        InvokeUi_default) {
   ShowAndVerifyUi();
 }
+
+IN_PROC_BROWSER_TEST_F(TabGroupEditorBubbleViewDialogBrowserTest,
+                       NewTabInGroup) {
+  ShowUi("SetUp");
+
+  TabGroupModel* group_model = browser()->tab_strip_model()->group_model();
+  std::vector<tab_groups::TabGroupId> group_list = group_model->ListTabGroups();
+  ASSERT_EQ(1u, group_list.size());
+  ASSERT_EQ(1u, group_model->GetTabGroup(group_list[0])->ListTabs().size());
+
+  BrowserView* browser_view = static_cast<BrowserView*>(browser()->window());
+  TabGroupHeader* header =
+      browser_view->tabstrip()->group_header(group_list[0]);
+  views::Widget* editor_bubble = GetEditorBubbleWidget(header);
+  ASSERT_NE(nullptr, editor_bubble);
+
+  views::Button* const new_tab_button =
+      views::Button::AsButton(editor_bubble->GetContentsView()->GetViewByID(
+          TabGroupEditorBubbleView::TAB_GROUP_HEADER_CXMENU_NEW_TAB_IN_GROUP));
+  EXPECT_NE(nullptr, new_tab_button);
+
+  ui::MouseEvent released_event(ui::ET_MOUSE_RELEASED, gfx::PointF(),
+                                gfx::PointF(), base::TimeTicks(), 0, 0);
+  views::test::ButtonTestApi(new_tab_button).NotifyClick(released_event);
+
+  EXPECT_EQ(2u, group_model->GetTabGroup(group_list[0])->ListTabs().size());
+}
+
+IN_PROC_BROWSER_TEST_F(TabGroupEditorBubbleViewDialogBrowserTest, Ungroup) {
+  ShowUi("SetUp");
+
+  TabStripModel* tsm = browser()->tab_strip_model();
+  ASSERT_EQ(1, tsm->count());
+  TabGroupModel* group_model = tsm->group_model();
+  std::vector<tab_groups::TabGroupId> group_list = group_model->ListTabGroups();
+  ASSERT_EQ(1u, group_list.size());
+  ASSERT_EQ(1u, group_model->GetTabGroup(group_list[0])->ListTabs().size());
+
+  BrowserView* browser_view = static_cast<BrowserView*>(browser()->window());
+  TabGroupHeader* header =
+      browser_view->tabstrip()->group_header(group_list[0]);
+  views::Widget* editor_bubble = GetEditorBubbleWidget(header);
+  ASSERT_NE(nullptr, editor_bubble);
+
+  views::Button* const ungroup_button =
+      views::Button::AsButton(editor_bubble->GetContentsView()->GetViewByID(
+          TabGroupEditorBubbleView::TAB_GROUP_HEADER_CXMENU_UNGROUP));
+  EXPECT_NE(nullptr, ungroup_button);
+
+  ui::MouseEvent released_event(ui::ET_MOUSE_RELEASED, gfx::PointF(),
+                                gfx::PointF(), base::TimeTicks(), 0, 0);
+  views::test::ButtonTestApi(ungroup_button).NotifyClick(released_event);
+
+  EXPECT_EQ(0u, group_model->ListTabGroups().size());
+  EXPECT_FALSE(group_model->ContainsTabGroup(group_list[0]));
+  EXPECT_EQ(1, tsm->count());
+}
+
+IN_PROC_BROWSER_TEST_F(TabGroupEditorBubbleViewDialogBrowserTest,
+                       CloseGroupClosesBrowser) {
+  ShowUi("SetUp");
+
+  TabGroupModel* group_model = browser()->tab_strip_model()->group_model();
+  std::vector<tab_groups::TabGroupId> group_list = group_model->ListTabGroups();
+  ASSERT_EQ(1u, group_list.size());
+  ASSERT_EQ(1u, group_model->GetTabGroup(group_list[0])->ListTabs().size());
+
+  BrowserView* browser_view = static_cast<BrowserView*>(browser()->window());
+  TabGroupHeader* header =
+      browser_view->tabstrip()->group_header(group_list[0]);
+  views::Widget* editor_bubble = GetEditorBubbleWidget(header);
+  ASSERT_NE(nullptr, editor_bubble);
+
+  views::Button* const close_group_button =
+      views::Button::AsButton(editor_bubble->GetContentsView()->GetViewByID(
+          TabGroupEditorBubbleView::TAB_GROUP_HEADER_CXMENU_CLOSE_GROUP));
+  EXPECT_NE(nullptr, close_group_button);
+
+  ui::MouseEvent released_event(ui::ET_MOUSE_RELEASED, gfx::PointF(),
+                                gfx::PointF(), base::TimeTicks(), 0, 0);
+  views::test::ButtonTestApi(close_group_button).NotifyClick(released_event);
+
+  EXPECT_EQ(0u, group_model->ListTabGroups().size());
+  EXPECT_FALSE(group_model->ContainsTabGroup(group_list[0]));
+  EXPECT_EQ(0, browser()->tab_strip_model()->count());
+  EXPECT_TRUE(browser()->IsAttemptingToCloseBrowser());
+}
diff --git a/chrome/browser/ui/views/tabs/tab_group_header.h b/chrome/browser/ui/views/tabs/tab_group_header.h
index b0318808..7596616 100644
--- a/chrome/browser/ui/views/tabs/tab_group_header.h
+++ b/chrome/browser/ui/views/tabs/tab_group_header.h
@@ -43,6 +43,8 @@
   void RemoveObserverFromWidget(views::Widget* widget);
 
  private:
+  friend class TabGroupEditorBubbleViewDialogBrowserTest;
+
   // Calculate the width for this View.
   int CalculateWidth() const;
 
@@ -60,6 +62,7 @@
 
     void Opened(views::Widget* bubble_widget);
     bool is_open() const { return is_open_; }
+    views::Widget* widget() const { return widget_; }
 
     // views::WidgetObserver:
     void OnWidgetDestroyed(views::Widget* widget) override;
diff --git a/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.cc b/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.cc
index 1c24248..148cc97 100644
--- a/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.cc
+++ b/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.cc
@@ -4,13 +4,15 @@
 
 #include "chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.h"
 
+#include <utility>
+
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/channel_info.h"
 #include "components/autofill/core/browser/logging/log_router.h"
-#include "components/grit/components_resources.h"
+#include "components/grit/dev_ui_components_resources.h"
 #include "components/version_info/version_info.h"
 #include "components/version_ui/version_handler_helper.h"
 #include "components/version_ui/version_ui_constants.h"
diff --git a/chrome/browser/ui/webui/crashes_ui.cc b/chrome/browser/ui/webui/crashes_ui.cc
index 121cac7..4a5e20c 100644
--- a/chrome/browser/ui/webui/crashes_ui.cc
+++ b/chrome/browser/ui/webui/crashes_ui.cc
@@ -7,6 +7,8 @@
 #include <stddef.h>
 
 #include <memory>
+#include <string>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -24,8 +26,8 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "components/crash/core/browser/crashes_ui_util.h"
-#include "components/grit/components_resources.h"
 #include "components/grit/components_scaled_resources.h"
+#include "components/grit/dev_ui_components_resources.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
index e7d239f2..6ac30f7 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
+++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
@@ -10,6 +10,7 @@
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
 #include "chrome/browser/extensions/activity_log/activity_log.h"
 #include "chrome/browser/extensions/api/developer_private/developer_private_api.h"
 #include "chrome/browser/extensions/chrome_test_extension_loader.h"
@@ -222,8 +223,15 @@
   }
 }
 
+// Flaky on Windows: crbug.com/
+#if defined(OS_WIN)
+#define MAYBE_ActivityLogInactiveWithoutSwitch \
+  DISABLED_ActivityLogInactiveWithoutSwitch
+#else
+#define MAYBE_ActivityLogInactiveWithoutSwitch ActivityLogInactiveWithoutSwitch
+#endif  // OS_WIN
 IN_PROC_BROWSER_TEST_F(ExtensionSettingsUIBrowserTest,
-                       ActivityLogInactiveWithoutSwitch) {
+                       MAYBE_ActivityLogInactiveWithoutSwitch) {
   // Navigate to chrome://extensions which is a whitelisted URL for the
   // chrome.activityLogPrivate API.
   GURL extensions_url("chrome://extensions");
diff --git a/chrome/browser/ui/webui/flags_ui_handler.cc b/chrome/browser/ui/webui/flags_ui_handler.cc
index 3661f83..a340b551 100644
--- a/chrome/browser/ui/webui/flags_ui_handler.cc
+++ b/chrome/browser/ui/webui/flags_ui_handler.cc
@@ -116,8 +116,10 @@
   std::string entry_internal_name;
   std::string enable_str;
   if (!args->GetString(0, &entry_internal_name) ||
-      !args->GetString(1, &enable_str))
+      !args->GetString(1, &enable_str) || entry_internal_name.empty()) {
+    NOTREACHED();
     return;
+  }
 
   about_flags::SetFeatureEntryEnabled(flags_storage_.get(), entry_internal_name,
                                       enable_str == "true");
diff --git a/chrome/browser/ui/webui/gcm_internals_ui.cc b/chrome/browser/ui/webui/gcm_internals_ui.cc
index 6fcce1a..44490238 100644
--- a/chrome/browser/ui/webui/gcm_internals_ui.cc
+++ b/chrome/browser/ui/webui/gcm_internals_ui.cc
@@ -20,7 +20,7 @@
 #include "components/gcm_driver/gcm_internals_constants.h"
 #include "components/gcm_driver/gcm_internals_helper.h"
 #include "components/gcm_driver/gcm_profile_service.h"
-#include "components/grit/components_resources.h"
+#include "components/grit/dev_ui_components_resources.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"
diff --git a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
index a87f8ca..0d40268 100644
--- a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
+++ b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/webui/interstitials/interstitial_ui.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/atomic_sequence_num.h"
 #include "base/strings/string_number_conversions.h"
@@ -23,7 +24,7 @@
 #include "chrome/browser/ssl/mitm_software_blocking_page.h"
 #include "chrome/common/buildflags.h"
 #include "chrome/common/url_constants.h"
-#include "components/grit/components_resources.h"
+#include "components/grit/dev_ui_components_resources.h"
 #include "components/safe_browsing/core/db/database_manager.h"
 #include "components/security_interstitials/content/bad_clock_blocking_page.h"
 #include "components/security_interstitials/content/origin_policy_ui.h"
diff --git a/chrome/browser/ui/webui/net_export_ui.cc b/chrome/browser/ui/webui/net_export_ui.cc
index 0924a6d7..93bfc84f 100644
--- a/chrome/browser/ui/webui/net_export_ui.cc
+++ b/chrome/browser/ui/webui/net_export_ui.cc
@@ -8,6 +8,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
@@ -29,7 +30,7 @@
 #include "chrome/browser/ui/chrome_select_file_policy.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/url_constants.h"
-#include "components/grit/components_resources.h"
+#include "components/grit/dev_ui_components_resources.h"
 #include "components/net_log/net_export_file_writer.h"
 #include "components/net_log/net_export_ui_constants.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc b/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
index 8f72bc2..c2a62bd 100644
--- a/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
+++ b/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
@@ -5,6 +5,8 @@
 #include "chrome/browser/ui/webui/ntp_tiles_internals_ui.h"
 
 #include <memory>
+#include <string>
+#include <vector>
 
 #include "base/bind.h"
 #include "build/build_config.h"
@@ -15,7 +17,7 @@
 #include "chrome/browser/search/suggestions/suggestions_service_factory.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/common/url_constants.h"
-#include "components/grit/components_resources.h"
+#include "components/grit/dev_ui_components_resources.h"
 #include "components/history/core/browser/top_sites.h"
 #include "components/image_fetcher/core/image_fetcher_impl.h"
 #include "components/ntp_tiles/features.h"
diff --git a/chrome/browser/ui/webui/policy_ui.cc b/chrome/browser/ui/webui/policy_ui.cc
index fcc27d5d..33b2a46 100644
--- a/chrome/browser/ui/webui/policy_ui.cc
+++ b/chrome/browser/ui/webui/policy_ui.cc
@@ -11,7 +11,7 @@
 #include "chrome/browser/ui/webui/policy_ui_handler.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/common/url_constants.h"
-#include "components/grit/components_resources.h"
+#include "components/grit/dev_ui_components_resources.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_ui.h"
 
diff --git a/chrome/browser/ui/webui/signin_internals_ui.cc b/chrome/browser/ui/webui/signin_internals_ui.cc
index 8f28899..011dc70c 100644
--- a/chrome/browser/ui/webui/signin_internals_ui.cc
+++ b/chrome/browser/ui/webui/signin_internals_ui.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/signin/about_signin_internals_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/common/url_constants.h"
-#include "components/grit/components_resources.h"
+#include "components/grit/dev_ui_components_resources.h"
 #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "content/public/browser/web_ui.h"
diff --git a/chrome/browser/ui/webui/user_actions/user_actions_ui.cc b/chrome/browser/ui/webui/user_actions/user_actions_ui.cc
index 82cd9fc..b350bd7e 100644
--- a/chrome/browser/ui/webui/user_actions/user_actions_ui.cc
+++ b/chrome/browser/ui/webui/user_actions/user_actions_ui.cc
@@ -9,7 +9,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/user_actions/user_actions_ui_handler.h"
 #include "chrome/common/url_constants.h"
-#include "components/grit/components_resources.h"
+#include "components/grit/dev_ui_components_resources.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"
diff --git a/chrome/browser/updates/update_notification_client.cc b/chrome/browser/updates/update_notification_client.cc
index 61805c8..8c7fd93 100644
--- a/chrome/browser/updates/update_notification_client.cc
+++ b/chrome/browser/updates/update_notification_client.cc
@@ -37,7 +37,25 @@
 }
 
 void UpdateNotificationClient::OnUserAction(const UserActionData& action_data) {
-  NOTIMPLEMENTED();
+  DCHECK(action_data.client_type ==
+         notifications::SchedulerClientType::kChromeUpdate);
+  auto* update_notification_service = get_service_callback_.Run();
+  DCHECK(update_notification_service);
+
+  switch (action_data.action_type) {
+    case notifications::UserActionType::kClick:
+      NOTIMPLEMENTED();
+      break;
+    case notifications::UserActionType::kButtonClick:
+      NOTIMPLEMENTED();
+      break;
+    case notifications::UserActionType::kDismiss:
+      update_notification_service->OnUserDismiss();
+      break;
+    default:
+      NOTREACHED();
+      break;
+  }
 }
 
 }  // namespace updates
diff --git a/chrome/browser/updates/update_notification_service.h b/chrome/browser/updates/update_notification_service.h
index 21b8311..d7c6f73 100644
--- a/chrome/browser/updates/update_notification_service.h
+++ b/chrome/browser/updates/update_notification_service.h
@@ -24,6 +24,9 @@
   // Validate the notification is ready to show.
   virtual bool IsReadyToDisplay() const = 0;
 
+  // Called when the notification is dismissed by user.
+  virtual void OnUserDismiss() = 0;
+
   ~UpdateNotificationService() override = default;
 
  protected:
diff --git a/chrome/browser/updates/update_notification_service_bridge.cc b/chrome/browser/updates/update_notification_service_bridge.cc
index 1c42630..575f7ea 100644
--- a/chrome/browser/updates/update_notification_service_bridge.cc
+++ b/chrome/browser/updates/update_notification_service_bridge.cc
@@ -70,4 +70,14 @@
                              base::TimeDelta::FromMilliseconds(interval)));
 }
 
+void UpdateUserDismissCount(int count) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_UpdateNotificationServiceBridge_updateUserDismissCount(env, count);
+}
+
+int GetUserDismissCount() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  return Java_UpdateNotificationServiceBridge_getUserDismissCount(env);
+}
+
 }  // namespace updates
diff --git a/chrome/browser/updates/update_notification_service_bridge.h b/chrome/browser/updates/update_notification_service_bridge.h
index 92350a8..ace9fea7 100644
--- a/chrome/browser/updates/update_notification_service_bridge.h
+++ b/chrome/browser/updates/update_notification_service_bridge.h
@@ -12,20 +12,26 @@
 
 // Functions for calling into UpdateNotifiactionServiceBridge.java.
 
-// Updates and persists |timestamp| in Android shared preference.
+// Updates and persists |timestamp| in Android SharedPreferences.
 void UpdateLastShownTimeStamp(base::Time timestamp);
 
-// Return persisted timestamp of last shown notification from Android shared
-// preference. Return nullopt if there is no data.
+// Returns persisted timestamp of last shown notification from Android
+// SharedPreferences. Return nullopt if there is no data.
 base::Optional<base::Time> GetLastShownTimeStamp();
 
-// Updates and persists |interval| in Android shared preference.
+// Updates and persists |interval| in Android SharedPreferences.
 void UpdateThrottleInterval(base::TimeDelta interval);
 
-// Return persisted interval that might be throttled from Android shared
-// preference. Return nullopt if there is no data.
+// Returns persisted interval that might be throttled from Android
+// SharedPreferences. Return nullopt if there is no data.
 base::Optional<base::TimeDelta> GetThrottleInterval();
 
+// Updates and persists |count| in Android SharedPreferences.
+void UpdateUserDismissCount(int count);
+
+// Returns persisted count from Android SharedPreferences.
+int GetUserDismissCount();
+
 }  // namespace updates
 
 #endif  // CHROME_BROWSER_UPDATES_UPDATE_NOTIFICATION_SERVICE_BRIDGE_H_
diff --git a/chrome/browser/updates/update_notification_service_impl.cc b/chrome/browser/updates/update_notification_service_impl.cc
index bbfdaff..fb8dcd6f 100644
--- a/chrome/browser/updates/update_notification_service_impl.cc
+++ b/chrome/browser/updates/update_notification_service_impl.cc
@@ -33,6 +33,10 @@
 // Maximum number of update notification should be cached in scheduler.
 constexpr int kNumMaxNotificationsLimit = 1;
 
+// Maxmium number of consecutive dismiss actions from user that should be
+// considered as negative feedback.
+constexpr int kNumConsecutiveDismissCountCap = 2;
+
 UpdateNotificationServiceImpl::UpdateNotificationServiceImpl(
     notifications::NotificationScheduleService* schedule_service)
     : schedule_service_(schedule_service),
@@ -103,4 +107,21 @@
   return schedule_params;
 }
 
+void UpdateNotificationServiceImpl::OnUserDismiss() {
+  int count = updates::GetUserDismissCount() + 1;
+  if (count >= kNumConsecutiveDismissCountCap) {
+    ApplyLinearThrottle();
+    count = 0;
+  }
+  updates::UpdateUserDismissCount(count);
+}
+
+void UpdateNotificationServiceImpl::ApplyLinearThrottle() {
+  auto scale = config_->throttle_interval_linear_co_scale;
+  auto offset =
+      base::TimeDelta::FromDays(config_->throttle_interval_linear_co_offset);
+  auto interval = GetThrottleInterval();
+  updates::UpdateThrottleInterval(scale * interval + offset);
+}
+
 }  // namespace updates
diff --git a/chrome/browser/updates/update_notification_service_impl.h b/chrome/browser/updates/update_notification_service_impl.h
index b988185..6307d7f 100644
--- a/chrome/browser/updates/update_notification_service_impl.h
+++ b/chrome/browser/updates/update_notification_service_impl.h
@@ -34,6 +34,8 @@
 
   bool IsReadyToDisplay() const override;
 
+  void OnUserDismiss() override;
+
   // Called after querying the |ClientOverview| struct from scheduler system
   // completed.
   void OnClientOverviewQueried(UpdateNotificationInfo data,
@@ -46,6 +48,9 @@
   // otherwise return the default interval from config.
   base::TimeDelta GetThrottleInterval() const;
 
+  // Apply linear throttle logic.
+  void ApplyLinearThrottle();
+
   // Used to schedule notification to show in the future. Must outlive this
   // class.
   notifications::NotificationScheduleService* schedule_service_;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index d44bc77..b31cf64 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -558,6 +558,7 @@
       "$root_gen_dir/chrome/android/chrome_apk_paks/locales/en-US.pak",
       "$root_gen_dir/chrome/android/chrome_apk_paks/resources.pak",
       "$root_gen_dir/components/components_resources.pak",
+      "$root_gen_dir/components/dev_ui_components_resources.pak",
       "$root_out_dir/browser_tests.pak",
       "//components/test/data/payments/",
       "//chrome/test/data/ssl/",
@@ -591,7 +592,10 @@
 
     # These are grit() rules so they are in $root_gen_dir.
     deps += [ "//components/resources" ]
-    sources += [ "$root_gen_dir/components/components_resources.pak" ]
+    sources += [
+      "$root_gen_dir/components/components_resources.pak",
+      "$root_gen_dir/components/dev_ui_components_resources.pak",
+    ]
 
     # These are repack() rules so they are in $root_out_dir.
     deps += [ "//chrome:browser_tests_pak" ]
diff --git a/chrome/test/base/in_process_browser_test_browsertest.cc b/chrome/test/base/in_process_browser_test_browsertest.cc
index c8f712a..a7abb83 100644
--- a/chrome/test/base/in_process_browser_test_browsertest.cc
+++ b/chrome/test/base/in_process_browser_test_browsertest.cc
@@ -21,6 +21,7 @@
 #include "content/public/common/content_switches.h"
 #include "net/base/filename_util.h"
 #include "net/base/net_errors.h"
+#include "net/dns/public/resolve_error_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -44,7 +45,8 @@
   explicit LoadFailObserver(content::WebContents* contents)
       : content::WebContentsObserver(contents),
         failed_load_(false),
-        error_code_(net::OK) { }
+        error_code_(net::OK),
+        resolve_error_info_(net::ResolveErrorInfo(net::OK)) {}
 
   void DidFinishNavigation(
       content::NavigationHandle* navigation_handle) override {
@@ -53,16 +55,21 @@
 
     failed_load_ = true;
     error_code_ = navigation_handle->GetNetErrorCode();
+    resolve_error_info_ = navigation_handle->GetResolveErrorInfo();
     validated_url_ = navigation_handle->GetURL();
   }
 
   bool failed_load() const { return failed_load_; }
   net::Error error_code() const { return error_code_; }
+  net::ResolveErrorInfo resolve_error_info() const {
+    return resolve_error_info_;
+  }
   const GURL& validated_url() const { return validated_url_; }
 
  private:
   bool failed_load_;
   net::Error error_code_;
+  net::ResolveErrorInfo resolve_error_info_;
   GURL validated_url_;
 
   DISALLOW_COPY_AND_ASSIGN(LoadFailObserver);
@@ -84,7 +91,8 @@
     LoadFailObserver observer(contents);
     ui_test_utils::NavigateToURL(browser(), url);
     EXPECT_TRUE(observer.failed_load());
-    EXPECT_EQ(net::ERR_NOT_IMPLEMENTED, observer.error_code());
+    EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, observer.error_code());
+    EXPECT_EQ(net::ERR_NOT_IMPLEMENTED, observer.resolve_error_info().error);
     EXPECT_EQ(url, observer.validated_url());
   }
 }
diff --git a/chrome/test/data/webui/new_tab_page/customize_dialog_focus_test.js b/chrome/test/data/webui/new_tab_page/customize_dialog_focus_test.js
new file mode 100644
index 0000000..a2fa2fd5
--- /dev/null
+++ b/chrome/test/data/webui/new_tab_page/customize_dialog_focus_test.js
@@ -0,0 +1,187 @@
+// 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 'chrome://new-tab-page/customize_dialog.js';
+
+import {BrowserProxy} from 'chrome://new-tab-page/browser_proxy.js';
+import {assertFocus, keydown, TestProxy} from 'chrome://test/new_tab_page/test_support.js';
+import {eventToPromise, flushTasks} from 'chrome://test/test_util.m.js';
+
+suite('NewTabPageCustomizeDialogFocusTest', () => {
+  /** @type {!CustomizeDialogElement} */
+  let customizeDialog;
+
+  /** @type {TestProxy} */
+  let testProxy;
+
+  function queryThemeIcons() {
+    return customizeDialog.shadowRoot.querySelectorAll(
+        '#themesContainer ntp-theme-icon');
+  }
+
+  setup(async () => {
+    PolymerTest.clearBody();
+
+    testProxy = new TestProxy();
+    BrowserProxy.instance_ = testProxy;
+
+    const colors = {frame: {value: 0xff000000}, activeTab: {value: 0xff0000ff}};
+    const themes = [];
+    for (let i = 0; i < 10; ++i) {
+      themes.push({id: i, label: `theme_${i}`, colors});
+    }
+    testProxy.handler.setResultFor('getChromeThemes', Promise.resolve({
+      chromeThemes: themes,
+    }));
+    customizeDialog = document.createElement('ntp-customize-dialog');
+    document.body.appendChild(customizeDialog);
+    await flushTasks();
+  });
+
+  test('right focuses right theme icon', async () => {
+    // Act.
+    const themeIcons = queryThemeIcons();
+    keydown(themeIcons[0], 'ArrowRight');
+
+    // Assert.
+    assertFocus(themeIcons[1]);
+  });
+
+  test('right wrap around focuses first theme icon', async () => {
+    // Act.
+    const themeIcons = queryThemeIcons();
+    keydown(themeIcons[themeIcons.length - 1], 'ArrowRight');
+
+    // Assert.
+    assertFocus(themeIcons[0]);
+  });
+
+  test('left focuses left theme icon', async () => {
+    // Act.
+    const themeIcons = queryThemeIcons();
+    keydown(themeIcons[1], 'ArrowLeft');
+
+    // Assert.
+    assertFocus(themeIcons[0]);
+  });
+
+  test('left wrap around focuses last theme icon', async () => {
+    // Act.
+    const themeIcons = queryThemeIcons();
+    keydown(themeIcons[0], 'ArrowLeft');
+
+    // Assert.
+    assertFocus(themeIcons[themeIcons.length - 1]);
+  });
+
+  test('right focuses left theme icon in RTL', async () => {
+    // Arrange.
+    customizeDialog.dir = 'rtl';
+
+    // Act.
+    const themeIcons = queryThemeIcons();
+    keydown(themeIcons[1], 'ArrowRight');
+
+    // Assert.
+    assertFocus(themeIcons[0]);
+  });
+
+  test('right wrap around focuses last theme icon in RTL', async () => {
+    // Arrange.
+    customizeDialog.dir = 'rtl';
+
+    // Act.
+    const themeIcons = queryThemeIcons();
+    keydown(themeIcons[0], 'ArrowRight');
+
+    // Assert.
+    assertFocus(themeIcons[themeIcons.length - 1]);
+  });
+
+  test('left focuses right theme icon in RTL', async () => {
+    // Arrange.
+    customizeDialog.dir = 'rtl';
+
+    // Act.
+    const themeIcons = queryThemeIcons();
+    keydown(themeIcons[0], 'ArrowLeft');
+
+    // Assert.
+    assertFocus(themeIcons[1]);
+  });
+
+  test('left wrap around focuses first theme icon in RTL', async () => {
+    // Arrange.
+    customizeDialog.dir = 'rtl';
+
+    // Act.
+    const themeIcons = queryThemeIcons();
+    keydown(themeIcons[themeIcons.length - 1], 'ArrowLeft');
+
+    // Assert.
+    assertFocus(themeIcons[0]);
+  });
+
+  test('down focuses below theme icon', async () => {
+    // Act.
+    const themeIcons = queryThemeIcons();
+    keydown(themeIcons[0], 'ArrowDown');
+
+    // Assert.
+    assertFocus(themeIcons[6]);
+  });
+
+  test('up focuses above theme icon', async () => {
+    // Act.
+    const themeIcons = queryThemeIcons();
+    keydown(themeIcons[6], 'ArrowUp');
+
+    // Assert.
+    assertFocus(themeIcons[0]);
+  });
+
+  test('down wrap around focuses top theme icon', async () => {
+    // Act.
+    const themeIcons = queryThemeIcons();
+    keydown(themeIcons[6], 'ArrowDown');
+
+    // Assert.
+    assertFocus(themeIcons[0]);
+  });
+
+  test('up wrap around focuses bottom theme icon', async () => {
+    // Act.
+    const themeIcons = queryThemeIcons();
+    keydown(themeIcons[0], 'ArrowDown');
+
+    // Assert.
+    assertFocus(themeIcons[6]);
+  });
+
+  test('enter clicks focused theme icon', async () => {
+    // Arrange.
+    const themeIcon = queryThemeIcons()[0];
+    themeIcon.focus();
+    const themeIconClicked = eventToPromise('click', themeIcon);
+
+    // Act.
+    keydown(themeIcon, 'Enter');
+
+    // Assert.
+    await themeIconClicked;
+  });
+
+  test('space clicks focused theme icon', async () => {
+    // Arrange.
+    const themeIcon = queryThemeIcons()[0];
+    themeIcon.focus();
+    const themeIconClicked = eventToPromise('click', themeIcon);
+
+    // Act.
+    keydown(themeIcon, ' ');
+
+    // Assert.
+    await themeIconClicked;
+  });
+});
diff --git a/chrome/test/data/webui/new_tab_page/most_visited_focus_test.js b/chrome/test/data/webui/new_tab_page/most_visited_focus_test.js
index 85440e3..8fdbbd0 100644
--- a/chrome/test/data/webui/new_tab_page/most_visited_focus_test.js
+++ b/chrome/test/data/webui/new_tab_page/most_visited_focus_test.js
@@ -8,7 +8,7 @@
 
 import {BrowserProxy} from 'chrome://new-tab-page/browser_proxy.js';
 import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
-import {keydown, TestProxy} from 'chrome://test/new_tab_page/test_support.js';
+import {assertFocus, keydown, TestProxy} from 'chrome://test/new_tab_page/test_support.js';
 import {eventToPromise, flushTasks} from 'chrome://test/test_util.m.js';
 
 suite('NewTabPageMostVisitedFocusTest', () => {
@@ -59,14 +59,6 @@
     await tilesRendered;
   }
 
-  /**
-   * @param {!HTMLElement} element
-   * @private
-   */
-  function assertFocus(element) {
-    assertEquals(element, getDeepActiveElement());
-  }
-
   setup(() => {
     PolymerTest.clearBody();
 
diff --git a/chrome/test/data/webui/new_tab_page/new_tab_page_interactive_test.js b/chrome/test/data/webui/new_tab_page/new_tab_page_interactive_test.js
index 7852507..981a292 100644
--- a/chrome/test/data/webui/new_tab_page/new_tab_page_interactive_test.js
+++ b/chrome/test/data/webui/new_tab_page/new_tab_page_interactive_test.js
@@ -38,3 +38,16 @@
 TEST_F('NewTabPageMostVisitedFocusTest', 'All', function() {
   mocha.run();
 });
+
+// eslint-disable-next-line no-var
+var NewTabPageCustomizeDialogFocusTest =
+    class extends NewTabPageInteractiveTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://new-tab-page/test_loader.html?module=new_tab_page/customize_dialog_focus_test.js';
+  }
+};
+
+TEST_F('NewTabPageCustomizeDialogFocusTest', 'All', function() {
+  mocha.run();
+});
diff --git a/chrome/test/data/webui/new_tab_page/test_support.js b/chrome/test/data/webui/new_tab_page/test_support.js
index 7ee5d1d..89769821 100644
--- a/chrome/test/data/webui/new_tab_page/test_support.js
+++ b/chrome/test/data/webui/new_tab_page/test_support.js
@@ -8,6 +8,8 @@
 import 'chrome://new-tab-page/skcolor.mojom-lite.js';
 import 'chrome://new-tab-page/new_tab_page.mojom-lite.js';
 
+import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
+import {keyDownOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
 import {TestBrowserProxy} from 'chrome://test/test_browser_proxy.m.js';
 
 export class TestProxy {
@@ -134,7 +136,7 @@
  * @param {string} key
  */
 export function keydown(element, key) {
-  element.dispatchEvent(new KeyboardEvent('keydown', {key: key}));
+  keyDownOn(element, '', [], key);
 }
 
 /**
@@ -147,3 +149,11 @@
   const actual = window.getComputedStyle(element).getPropertyValue(name).trim();
   assertEquals(expected, actual);
 }
+
+/**
+ * Asserts that an element is focused.
+ * @param {!HTMLElement} element The element to test.
+ */
+export function assertFocus(element) {
+  assertEquals(element, getDeepActiveElement());
+}
diff --git a/chrome/test/enterprise/e2e/policy/cloud_management_enrollment_token/cloud_enrollment_webdriver.py b/chrome/test/enterprise/e2e/policy/cloud_management_enrollment_token/cloud_enrollment_webdriver.py
index 2811adf..54737b7 100644
--- a/chrome/test/enterprise/e2e/policy/cloud_management_enrollment_token/cloud_enrollment_webdriver.py
+++ b/chrome/test/enterprise/e2e/policy/cloud_management_enrollment_token/cloud_enrollment_webdriver.py
@@ -11,10 +11,6 @@
 
 def main(argv):
   options = webdriver.ChromeOptions()
-  # Add option for enrolling to the dev DMServer
-  options.add_argument(
-      "device-management-url=https://crosman-qa.sandbox.google.com/devicemanagement/data/api"
-  )
   os.environ["CHROME_LOG_FILE"] = r"c:\temp\chrome_log.txt"
   driver = test_util.create_chrome_webdriver(chrome_options=options)
 
diff --git a/chrome/test/enterprise/e2e/policy/cloud_management_enrollment_token/cloud_management_enrollment_token.py b/chrome/test/enterprise/e2e/policy/cloud_management_enrollment_token/cloud_management_enrollment_token.py
index eb7bbdc..8d0fd38 100644
--- a/chrome/test/enterprise/e2e/policy/cloud_management_enrollment_token/cloud_management_enrollment_token.py
+++ b/chrome/test/enterprise/e2e/policy/cloud_management_enrollment_token/cloud_management_enrollment_token.py
@@ -2,12 +2,19 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from absl import flags
 import os
 
 from infra import ChromeEnterpriseTestCase
 from chrome_ent_test.infra.core import before_all, category, environment, test
 
 
+FLAGS = flags.FLAGS
+flags.DEFINE_string(
+    'enrollToken', None,
+    'The enrollment token to use, it overwrites the default token')
+
+
 @category("chrome_only")
 @environment(file="../policy_test.asset.textpb")
 class CloudManagementEnrollmentTokenTest(ChromeEnterpriseTestCase):
@@ -20,10 +27,12 @@
     self.InstallWebDriver('client2012')
 
   @test
-  def test_browser_enrolled(self):
-    path = "gs://%s/secrets/enrollToken" % self.gsbucket
-    cmd = r'gsutil cat ' + path
-    token = self.RunCommand('win2012-dc', cmd).rstrip()
+  def test_browser_enrolled_prod(self):
+    token = FLAGS.enrollToken
+    if token == None:
+      path = "gs://%s/secrets/enrollToken" % self.gsbucket
+      cmd = r'gsutil cat ' + path
+      token = self.RunCommand('win2012-dc', cmd).rstrip()
     self.SetPolicy('win2012-dc', r'CloudManagementEnrollmentToken', token,
                    'String')
     self.RunCommand('client2012', 'gpupdate /force')
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn
index 3ef8091c..a3da19b 100644
--- a/chromecast/browser/BUILD.gn
+++ b/chromecast/browser/BUILD.gn
@@ -419,8 +419,6 @@
       "webview/webview_controller.h",
       "webview/webview_grpc_service.cc",
       "webview/webview_grpc_service.h",
-      "webview/webview_layout_manager.cc",
-      "webview/webview_layout_manager.h",
       "webview/webview_navigation_throttle.cc",
       "webview/webview_navigation_throttle.h",
       "webview/webview_rpc_instance.cc",
diff --git a/chromecast/browser/accessibility/OWNERS b/chromecast/browser/accessibility/OWNERS
new file mode 100644
index 0000000..311eed1
--- /dev/null
+++ b/chromecast/browser/accessibility/OWNERS
@@ -0,0 +1 @@
+rmrossi@chromium.org
diff --git a/chromecast/browser/accessibility/touch_exploration_controller.cc b/chromecast/browser/accessibility/touch_exploration_controller.cc
index 751e323..faaae8d2 100644
--- a/chromecast/browser/accessibility/touch_exploration_controller.cc
+++ b/chromecast/browser/accessibility/touch_exploration_controller.cc
@@ -197,7 +197,7 @@
                            gesture_start_height_) != NO_EDGE) {
     SET_STATE(ONE_FINGER_PASSTHROUGH);
     initial_press_ = std::make_unique<ui::TouchEvent>(touch_event);
-    last_unused_finger_event_.reset(new ui::TouchEvent(touch_event));
+    passthrough_offset_ = gfx::Vector2dF(0, 0);
     return SendEvent(continuation, &event);
   }
 
@@ -215,6 +215,12 @@
         DVLOG(1) << "Reset to no fingers in Rewrite event because the touch  "
                     "release or cancel was on the edge of the screen.";
       }
+      if (side_gesture_pass_through_) {
+        // Don't discard event when side gesture pass through is enabled. It
+        // interferes with gesture detector logic further down the processing
+        // stack.
+        return SendEvent(continuation, &event);
+      }
       return DiscardEvent(continuation);
     }
   }
diff --git a/chromecast/browser/webview/platform_views_grpc_service.cc b/chromecast/browser/webview/platform_views_grpc_service.cc
index 41b763d..23fa0c18 100644
--- a/chromecast/browser/webview/platform_views_grpc_service.cc
+++ b/chromecast/browser/webview/platform_views_grpc_service.cc
@@ -18,11 +18,12 @@
     std::unique_ptr<webview::PlatformViewsService::AsyncService> service,
     std::unique_ptr<grpc::ServerCompletionQueue> cq,
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
-    WebContentsProvider* web_contents_provider)
+    WebContentsProvider* web_contents_provider,
+    CastWindowManager* cast_window_manager)
     : ui_task_runner_(std::move(ui_task_runner)),
       cq_(std::move(cq)),
       service_(std::move(service)),
-      window_manager_(nullptr),
+      window_manager_(cast_window_manager),
       web_contents_provider_(web_contents_provider) {
   base::PlatformThread::Create(0, this, &rpc_thread_);
 }
diff --git a/chromecast/browser/webview/platform_views_grpc_service.h b/chromecast/browser/webview/platform_views_grpc_service.h
index 65904266..ec636a20 100644
--- a/chromecast/browser/webview/platform_views_grpc_service.h
+++ b/chromecast/browser/webview/platform_views_grpc_service.h
@@ -15,7 +15,10 @@
 #include "third_party/grpc/src/include/grpcpp/server.h"
 
 namespace chromecast {
+
+class CastWindowManager;
 class WebContentsProvider;
+
 // This is a service that provides a GRPC interface to create and control
 // webviews, as well as control cast apps. See the proto file for commands.
 class PlatformViewsAsyncService : public base::PlatformThread::Delegate {
@@ -24,7 +27,8 @@
       std::unique_ptr<webview::PlatformViewsService::AsyncService> service,
       std::unique_ptr<grpc::ServerCompletionQueue> cq,
       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
-      WebContentsProvider* web_contents_provider);
+      WebContentsProvider* web_contents_provider,
+      CastWindowManager* cast_window_manager = nullptr);
   ~PlatformViewsAsyncService() override;
 
  private:
diff --git a/chromecast/browser/webview/web_content_controller.cc b/chromecast/browser/webview/web_content_controller.cc
index b94e5b4..f120012 100644
--- a/chromecast/browser/webview/web_content_controller.cc
+++ b/chromecast/browser/webview/web_content_controller.cc
@@ -8,7 +8,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chromecast/base/version.h"
 #include "chromecast/browser/webview/proto/webview.pb.h"
-#include "chromecast/browser/webview/webview_layout_manager.h"
 #include "chromecast/browser/webview/webview_navigation_throttle.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browsing_data_remover.h"
@@ -139,9 +138,7 @@
 void WebContentController::AttachTo(aura::Window* window, int window_id) {
   content::WebContents* contents = GetWebContents();
   auto* contents_window = contents->GetNativeView();
-  window->SetLayoutManager(new WebviewLayoutManager(window));
   contents_window->set_id(window_id);
-  contents_window->SetBounds(gfx::Rect(window->bounds().size()));
   // The aura window is hidden to avoid being shown via the usual layer method,
   // instead it is shows via a SurfaceDrawQuad by exo.
   contents_window->Hide();
diff --git a/chromecast/browser/webview/webview_controller.cc b/chromecast/browser/webview/webview_controller.cc
index 62f112bb..a03c0a1 100644
--- a/chromecast/browser/webview/webview_controller.cc
+++ b/chromecast/browser/webview/webview_controller.cc
@@ -12,7 +12,6 @@
 #include "chromecast/base/version.h"
 #include "chromecast/browser/cast_web_contents_impl.h"
 #include "chromecast/browser/webview/proto/webview.pb.h"
-#include "chromecast/browser/webview/webview_layout_manager.h"
 #include "chromecast/browser/webview/webview_navigation_throttle.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browsing_data_remover.h"
diff --git a/chromecast/browser/webview/webview_layout_manager.cc b/chromecast/browser/webview/webview_layout_manager.cc
deleted file mode 100644
index fed2b397..0000000
--- a/chromecast/browser/webview/webview_layout_manager.cc
+++ /dev/null
@@ -1,34 +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 "chromecast/browser/webview/webview_layout_manager.h"
-
-#include "ui/aura/window.h"
-
-namespace chromecast {
-
-WebviewLayoutManager::WebviewLayoutManager(aura::Window* root) : root_(root) {}
-
-WebviewLayoutManager::~WebviewLayoutManager() {}
-
-void WebviewLayoutManager::OnWindowResized() {
-  for (aura::Window* child : root_->children())
-    SetChildBoundsDirect(child, gfx::Rect(root_->bounds().size()));
-}
-
-void WebviewLayoutManager::OnWindowAddedToLayout(aura::Window* child) {}
-
-void WebviewLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {}
-
-void WebviewLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {}
-
-void WebviewLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child,
-                                                          bool visible) {}
-
-void WebviewLayoutManager::SetChildBounds(aura::Window* child,
-                                          const gfx::Rect& requested_bounds) {
-  SetChildBoundsDirect(child, requested_bounds);
-}
-
-}  // namespace chromecast
diff --git a/chromecast/browser/webview/webview_layout_manager.h b/chromecast/browser/webview/webview_layout_manager.h
deleted file mode 100644
index 194b85d..0000000
--- a/chromecast/browser/webview/webview_layout_manager.h
+++ /dev/null
@@ -1,36 +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 CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_LAYOUT_MANAGER_H_
-#define CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_LAYOUT_MANAGER_H_
-
-#include "base/macros.h"
-#include "ui/aura/layout_manager.h"
-
-namespace chromecast {
-
-// Resizes the provided window to be the parent window's size.
-class WebviewLayoutManager : public aura::LayoutManager {
- public:
-  WebviewLayoutManager(aura::Window* root);
-  ~WebviewLayoutManager() override;
-
-  void OnWindowResized() override;
-  void OnWindowAddedToLayout(aura::Window* child) override;
-  void OnWillRemoveWindowFromLayout(aura::Window* child) override;
-  void OnWindowRemovedFromLayout(aura::Window* child) override;
-  void OnChildWindowVisibilityChanged(aura::Window* child,
-                                      bool visible) override;
-  void SetChildBounds(aura::Window* child,
-                      const gfx::Rect& requested_bounds) override;
-
- private:
-  aura::Window* root_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebviewLayoutManager);
-};
-
-}  // namespace chromecast
-
-#endif  // CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_LAYOUT_MANAGER_H_
diff --git a/chromeos/components/sync_wifi/BUILD.gn b/chromeos/components/sync_wifi/BUILD.gn
index a16ac09..60a36c5 100644
--- a/chromeos/components/sync_wifi/BUILD.gn
+++ b/chromeos/components/sync_wifi/BUILD.gn
@@ -16,6 +16,8 @@
     "synced_network_updater.h",
     "synced_network_updater_impl.cc",
     "synced_network_updater_impl.h",
+    "timer_factory.cc",
+    "timer_factory.h",
     "wifi_configuration_bridge.cc",
     "wifi_configuration_bridge.h",
     "wifi_configuration_sync_service.cc",
@@ -38,8 +40,12 @@
 source_set("test_support") {
   testonly = true
   sources = [
+    "fake_one_shot_timer.cc",
+    "fake_one_shot_timer.h",
     "fake_pending_network_configuration_tracker.cc",
     "fake_pending_network_configuration_tracker.h",
+    "fake_timer_factory.cc",
+    "fake_timer_factory.h",
     "test_data_generator.cc",
     "test_data_generator.h",
   ]
diff --git a/chromeos/components/sync_wifi/fake_one_shot_timer.cc b/chromeos/components/sync_wifi/fake_one_shot_timer.cc
new file mode 100644
index 0000000..63b5fb03
--- /dev/null
+++ b/chromeos/components/sync_wifi/fake_one_shot_timer.cc
@@ -0,0 +1,26 @@
+// 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 "chromeos/components/sync_wifi/fake_one_shot_timer.h"
+
+#include "base/callback.h"
+#include "base/run_loop.h"
+#include "base/test/simple_test_tick_clock.h"
+
+namespace chromeos {
+
+namespace sync_wifi {
+
+FakeOneShotTimer::FakeOneShotTimer(
+    base::OnceCallback<void(const base::UnguessableToken&)> destructor_callback)
+    : destructor_callback_(std::move(destructor_callback)),
+      id_(base::UnguessableToken::Create()) {}
+
+FakeOneShotTimer::~FakeOneShotTimer() {
+  std::move(destructor_callback_).Run(id_);
+}
+
+}  // namespace sync_wifi
+
+}  // namespace chromeos
diff --git a/chromeos/components/sync_wifi/fake_one_shot_timer.h b/chromeos/components/sync_wifi/fake_one_shot_timer.h
new file mode 100644
index 0000000..0b94f188
--- /dev/null
+++ b/chromeos/components/sync_wifi/fake_one_shot_timer.h
@@ -0,0 +1,39 @@
+// 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 CHROMEOS_COMPONENTS_SYNC_WIFI_FAKE_ONE_SHOT_TIMER_H_
+#define CHROMEOS_COMPONENTS_SYNC_WIFI_FAKE_ONE_SHOT_TIMER_H_
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/timer/mock_timer.h"
+#include "base/unguessable_token.h"
+
+namespace chromeos {
+
+namespace sync_wifi {
+
+// Fake base::OneShotTimer implementation, which extends MockOneShotTimer and
+// provides a mechanism for alerting its creator when it's destroyed.
+class FakeOneShotTimer : public base::MockOneShotTimer {
+ public:
+  FakeOneShotTimer(base::OnceCallback<void(const base::UnguessableToken&)>
+                       destructor_callback);
+  ~FakeOneShotTimer() override;
+
+  const base::UnguessableToken& id() const { return id_; }
+
+ private:
+  base::OnceCallback<void(const base::UnguessableToken&)> destructor_callback_;
+  base::UnguessableToken id_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeOneShotTimer);
+};
+
+}  // namespace sync_wifi
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_SYNC_WIFI_FAKE_ONE_SHOT_TIMER_H_
diff --git a/chromeos/components/sync_wifi/fake_pending_network_configuration_tracker.cc b/chromeos/components/sync_wifi/fake_pending_network_configuration_tracker.cc
index b1a6417..a8e5b2b 100644
--- a/chromeos/components/sync_wifi/fake_pending_network_configuration_tracker.cc
+++ b/chromeos/components/sync_wifi/fake_pending_network_configuration_tracker.cc
@@ -40,14 +40,13 @@
 }
 
 void FakePendingNetworkConfigurationTracker::IncrementCompletedAttempts(
-    const std::string& change_id,
+    const std::string& change_guid,
     const NetworkIdentifier& id) {
-  base::Optional<PendingNetworkConfigurationUpdate> existing_update =
-      GetPendingUpdate(change_id, id);
-  id_to_pending_update_map_.emplace(
-      std::piecewise_construct, std::forward_as_tuple(id),
-      std::forward_as_tuple(id, change_id, existing_update->specifics(),
-                            existing_update->completed_attempts() + 1));
+  PendingNetworkConfigurationUpdate& existing_update =
+      id_to_pending_update_map_.at(id);
+  existing_update.SetCompletedAttemptsForTesting(
+      existing_update.completed_attempts() + 1);
+
   id_to_completed_attempts_map_[id]++;
 }
 
diff --git a/chromeos/components/sync_wifi/fake_timer_factory.cc b/chromeos/components/sync_wifi/fake_timer_factory.cc
new file mode 100644
index 0000000..71e3413
--- /dev/null
+++ b/chromeos/components/sync_wifi/fake_timer_factory.cc
@@ -0,0 +1,42 @@
+// 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 "chromeos/components/sync_wifi/fake_timer_factory.h"
+
+#include "base/logging.h"
+#include "base/unguessable_token.h"
+#include "chromeos/components/sync_wifi/fake_one_shot_timer.h"
+
+namespace chromeos {
+
+namespace sync_wifi {
+
+FakeTimerFactory::FakeTimerFactory() = default;
+
+FakeTimerFactory::~FakeTimerFactory() = default;
+
+std::unique_ptr<base::OneShotTimer> FakeTimerFactory::CreateOneShotTimer() {
+  auto mock_timer = std::make_unique<FakeOneShotTimer>(
+      base::BindOnce(&FakeTimerFactory::OnOneShotTimerDeleted,
+                     weak_ptr_factory_.GetWeakPtr()));
+  id_to_timer_map_[mock_timer->id()] = mock_timer.get();
+  return mock_timer;
+}
+
+void FakeTimerFactory::FireAll() {
+  // Make a copy because firing a timer will usually destroy it.  This calls
+  // OnOneShotTimerDeleted and removes it from |id_to_timer_map_|.
+  auto id_to_timer_map_copy = id_to_timer_map_;
+  for (auto it : id_to_timer_map_copy)
+    it.second->Fire();
+}
+
+void FakeTimerFactory::OnOneShotTimerDeleted(
+    const base::UnguessableToken& deleted_timer_id) {
+  id_to_timer_map_.erase(deleted_timer_id);
+}
+
+}  // namespace sync_wifi
+
+}  // namespace chromeos
diff --git a/chromeos/components/sync_wifi/fake_timer_factory.h b/chromeos/components/sync_wifi/fake_timer_factory.h
new file mode 100644
index 0000000..0fcce0ec
--- /dev/null
+++ b/chromeos/components/sync_wifi/fake_timer_factory.h
@@ -0,0 +1,49 @@
+// 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 CHROMEOS_COMPONENTS_SYNC_WIFI_FAKE_TIMER_FACTORY_H_
+#define CHROMEOS_COMPONENTS_SYNC_WIFI_FAKE_TIMER_FACTORY_H_
+
+#include <memory>
+#include <string>
+
+#include "base/containers/flat_map.h"
+#include "base/single_thread_task_runner.h"
+#include "base/timer/timer.h"
+#include "chromeos/components/sync_wifi/fake_one_shot_timer.h"
+#include "chromeos/components/sync_wifi/timer_factory.h"
+
+namespace base {
+class OneShotTimer;
+class UnguessableToken;
+}  // namespace base
+
+namespace chromeos {
+
+namespace sync_wifi {
+
+class FakeTimerFactory : public TimerFactory {
+ public:
+  FakeTimerFactory();
+  ~FakeTimerFactory() override;
+
+  // TimerFactory:
+  std::unique_ptr<base::OneShotTimer> CreateOneShotTimer() override;
+
+  void FireAll();
+
+ private:
+  void OnOneShotTimerDeleted(const base::UnguessableToken& deleted_timer_id);
+
+  base::flat_map<base::UnguessableToken, FakeOneShotTimer*> id_to_timer_map_;
+  base::WeakPtrFactory<FakeTimerFactory> weak_ptr_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(FakeTimerFactory);
+};
+
+}  // namespace sync_wifi
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_SYNC_WIFI_FAKE_TIMER_FACTORY_H_
\ No newline at end of file
diff --git a/chromeos/components/sync_wifi/pending_network_configuration_tracker.h b/chromeos/components/sync_wifi/pending_network_configuration_tracker.h
index e1f2a40..f03698d5 100644
--- a/chromeos/components/sync_wifi/pending_network_configuration_tracker.h
+++ b/chromeos/components/sync_wifi/pending_network_configuration_tracker.h
@@ -47,7 +47,8 @@
       const std::string& change_guid,
       const NetworkIdentifier& id) = 0;
 
-  // Increments the number of completed attempts for the given update.
+  // Increments the number of completed attempts for the given update.  Be sure
+  // that the |change_guid| and |ssid| exist in the tracker before calling.
   virtual void IncrementCompletedAttempts(const std::string& change_guid,
                                           const NetworkIdentifier& id) = 0;
 
diff --git a/chromeos/components/sync_wifi/pending_network_configuration_update.h b/chromeos/components/sync_wifi/pending_network_configuration_update.h
index 2fc53fa2..9c6cb20a 100644
--- a/chromeos/components/sync_wifi/pending_network_configuration_update.h
+++ b/chromeos/components/sync_wifi/pending_network_configuration_update.h
@@ -51,6 +51,12 @@
   bool IsDeleteOperation() const;
 
  private:
+  friend class FakePendingNetworkConfigurationTracker;
+
+  void SetCompletedAttemptsForTesting(int completed_attempts) {
+    completed_attempts_ = completed_attempts;
+  }
+
   NetworkIdentifier id_;
   std::string change_guid_;
   base::Optional<sync_pb::WifiConfigurationSpecificsData> specifics_;
diff --git a/chromeos/components/sync_wifi/synced_network_updater_impl.cc b/chromeos/components/sync_wifi/synced_network_updater_impl.cc
index 8f98fe36..9601bd1 100644
--- a/chromeos/components/sync_wifi/synced_network_updater_impl.cc
+++ b/chromeos/components/sync_wifi/synced_network_updater_impl.cc
@@ -8,6 +8,7 @@
 #include "base/guid.h"
 #include "base/values.h"
 #include "chromeos/components/sync_wifi/network_type_conversions.h"
+#include "chromeos/components/sync_wifi/timer_factory.h"
 #include "chromeos/network/network_configuration_handler.h"
 #include "chromeos/network/network_profile_handler.h"
 #include "chromeos/network/network_state.h"
@@ -19,14 +20,29 @@
 
 namespace sync_wifi {
 
+namespace {
+
+const int kMaxRetries = 3;
+const char kTimedOutErrorMsg[] = "Timed out";
+constexpr base::TimeDelta kTimeout = base::TimeDelta::FromMinutes(1);
+
+}  // namespace
+
 SyncedNetworkUpdaterImpl::SyncedNetworkUpdaterImpl(
     std::unique_ptr<PendingNetworkConfigurationTracker> tracker,
-    network_config::mojom::CrosNetworkConfig* cros_network_config)
-    : tracker_(std::move(tracker)), cros_network_config_(cros_network_config) {
+    network_config::mojom::CrosNetworkConfig* cros_network_config,
+    std::unique_ptr<TimerFactory> timer_factory)
+    : tracker_(std::move(tracker)),
+      cros_network_config_(cros_network_config),
+      timer_factory_(std::move(timer_factory)) {
   cros_network_config_->AddObserver(
       cros_network_config_observer_receiver_.BindNewPipeAndPassRemote());
   // Load the current list of networks.
   OnNetworkStateListChanged();
+  std::vector<PendingNetworkConfigurationUpdate> updates =
+      tracker_->GetPendingUpdates();
+  for (const PendingNetworkConfigurationUpdate& update : updates)
+    Retry(update);
 }
 
 SyncedNetworkUpdaterImpl::~SyncedNetworkUpdaterImpl() = default;
@@ -34,12 +50,21 @@
 void SyncedNetworkUpdaterImpl::AddOrUpdateNetwork(
     const sync_pb::WifiConfigurationSpecificsData& specifics) {
   auto id = NetworkIdentifier::FromProto(specifics);
-  network_config::mojom::NetworkStatePropertiesPtr existing_network =
-      FindLocalNetwork(id);
   std::string change_guid = tracker_->TrackPendingUpdate(id, specifics);
+  StartAddOrUpdateOperation(change_guid, id, specifics);
+}
+
+void SyncedNetworkUpdaterImpl::StartAddOrUpdateOperation(
+    const std::string& change_guid,
+    const NetworkIdentifier& id,
+    const sync_pb::WifiConfigurationSpecificsData& specifics) {
+  network_config::mojom::NetworkStatePropertiesPtr existing_network =
+      FindMojoNetwork(id);
   network_config::mojom::ConfigPropertiesPtr config =
       MojoNetworkConfigFromProto(specifics);
 
+  StartTimer(change_guid, id);
+
   if (existing_network) {
     cros_network_config_->SetProperties(
         existing_network->guid, std::move(config),
@@ -47,29 +72,36 @@
                        weak_ptr_factory_.GetWeakPtr(), change_guid, id));
     return;
   }
+
   cros_network_config_->ConfigureNetwork(
-      std::move(config), /* shared= */ false,
+      std::move(config), /*shared=*/false,
       base::BindOnce(&SyncedNetworkUpdaterImpl::OnConfigureNetworkResult,
                      weak_ptr_factory_.GetWeakPtr(), change_guid, id));
 }
 
 void SyncedNetworkUpdaterImpl::RemoveNetwork(const NetworkIdentifier& id) {
   network_config::mojom::NetworkStatePropertiesPtr network =
-      FindLocalNetwork(id);
+      FindMojoNetwork(id);
   if (!network)
     return;
 
   std::string change_guid =
       tracker_->TrackPendingUpdate(id, /*specifics=*/base::nullopt);
+  StartDeleteOperation(change_guid, id, network->guid);
+}
 
+void SyncedNetworkUpdaterImpl::StartDeleteOperation(
+    const std::string& change_guid,
+    const NetworkIdentifier& id,
+    std::string guid) {
+  StartTimer(change_guid, id);
   cros_network_config_->ForgetNetwork(
-      network->guid,
-      base::BindOnce(&SyncedNetworkUpdaterImpl::OnForgetNetworkResult,
-                     weak_ptr_factory_.GetWeakPtr(), change_guid, id));
+      guid, base::BindOnce(&SyncedNetworkUpdaterImpl::OnForgetNetworkResult,
+                           weak_ptr_factory_.GetWeakPtr(), change_guid, id));
 }
 
 network_config::mojom::NetworkStatePropertiesPtr
-SyncedNetworkUpdaterImpl::FindLocalNetwork(const NetworkIdentifier& id) {
+SyncedNetworkUpdaterImpl::FindMojoNetwork(const NetworkIdentifier& id) {
   for (const network_config::mojom::NetworkStatePropertiesPtr& network :
        networks_) {
     if (id == NetworkIdentifier::FromMojoNetwork(network))
@@ -83,7 +115,7 @@
       network_config::mojom::NetworkFilter::New(
           network_config::mojom::FilterType::kConfigured,
           network_config::mojom::NetworkType::kWiFi,
-          /* limit= */ 0),
+          /*limit=*/0),
       base::BindOnce(&SyncedNetworkUpdaterImpl::OnGetNetworkList,
                      base::Unretained(this)));
 }
@@ -98,6 +130,7 @@
                                        const std::string& error_name) {
   NET_LOG(ERROR) << "Failed to update id:" << id.SerializeToString()
                  << " error:" << error_name;
+  HandleShillResult(change_guid, id, /*is_success=*/false);
 }
 
 void SyncedNetworkUpdaterImpl::OnConfigureNetworkResult(
@@ -105,38 +138,73 @@
     const NetworkIdentifier& id,
     const base::Optional<std::string>& guid,
     const std::string& error_message) {
-  if (!guid) {
-    OnError(change_guid, id, "Failed to configure network.");
-    return;
+  if (guid) {
+    VLOG(1) << "Successfully configured network with id "
+            << id.SerializeToString();
+  } else {
+    NET_LOG(ERROR) << "Failed to configure network with id "
+                   << id.SerializeToString() << ". " << error_message;
   }
-  VLOG(1) << "Successfully updated network with id " << id.SerializeToString();
-  CleanupUpdate(change_guid, id);
+  HandleShillResult(change_guid, id, guid.has_value());
 }
 
 void SyncedNetworkUpdaterImpl::OnSetPropertiesResult(
     const std::string& change_guid,
     const NetworkIdentifier& id,
-    bool success,
+    bool is_success,
     const std::string& error_message) {
-  if (!success) {
-    OnError(change_guid, id, "Failed to update properties on network.");
-    return;
+  if (is_success) {
+    VLOG(1) << "Successfully updated network with id "
+            << id.SerializeToString();
+  } else {
+    NET_LOG(ERROR) << "Failed to update network with id "
+                   << id.SerializeToString();
   }
-  VLOG(1) << "Successfully updated network with id " << id.SerializeToString();
-  CleanupUpdate(change_guid, id);
+  HandleShillResult(change_guid, id, is_success);
 }
 
 void SyncedNetworkUpdaterImpl::OnForgetNetworkResult(
     const std::string& change_guid,
     const NetworkIdentifier& id,
-    bool success) {
-  if (!success) {
-    OnError(change_guid, id, "Failed to remove network.");
+    bool is_success) {
+  if (is_success)
+    VLOG(1) << "Successfully deleted network with id "
+            << id.SerializeToString();
+  else
+    NET_LOG(ERROR) << "Failed to remove network with id "
+                   << id.SerializeToString();
+
+  HandleShillResult(change_guid, id, is_success);
+}
+
+void SyncedNetworkUpdaterImpl::HandleShillResult(const std::string& change_guid,
+                                                 const NetworkIdentifier& id,
+                                                 bool is_success) {
+  change_guid_to_timer_map_.erase(change_guid);
+  if (is_success) {
+    tracker_->MarkComplete(change_guid, id);
     return;
   }
 
-  VLOG(1) << "Successfully deleted network with id " << id.SerializeToString();
-  CleanupUpdate(change_guid, id);
+  if (!tracker_->GetPendingUpdate(change_guid, id)) {
+    VLOG(1) << "Update to network " << id.SerializeToString()
+            << " with change_guid " << change_guid
+            << " is no longer pending.  This is usually because it was "
+               "preempted by another update to the same network.";
+    return;
+  }
+  tracker_->IncrementCompletedAttempts(change_guid, id);
+
+  base::Optional<PendingNetworkConfigurationUpdate> update =
+      tracker_->GetPendingUpdate(change_guid, id);
+  if (update->completed_attempts() >= kMaxRetries) {
+    LOG(ERROR) << "Ran out of retries updating network with id "
+               << id.SerializeToString();
+    tracker_->MarkComplete(change_guid, id);
+    return;
+  }
+
+  Retry(*update);
 }
 
 void SyncedNetworkUpdaterImpl::CleanupUpdate(const std::string& change_guid,
@@ -144,6 +212,33 @@
   tracker_->MarkComplete(change_guid, id);
 }
 
+void SyncedNetworkUpdaterImpl::Retry(
+    const PendingNetworkConfigurationUpdate& update) {
+  if (update.IsDeleteOperation()) {
+    network_config::mojom::NetworkStatePropertiesPtr network =
+        FindMojoNetwork(update.id());
+    if (!network) {
+      tracker_->MarkComplete(update.change_guid(), update.id());
+      return;
+    }
+
+    StartDeleteOperation(update.change_guid(), update.id(), network->guid);
+    return;
+  }
+
+  StartAddOrUpdateOperation(update.change_guid(), update.id(),
+                            update.specifics().value());
+}
+
+void SyncedNetworkUpdaterImpl::StartTimer(const std::string& change_guid,
+                                          const NetworkIdentifier& id) {
+  change_guid_to_timer_map_[change_guid] = timer_factory_->CreateOneShotTimer();
+  change_guid_to_timer_map_[change_guid]->Start(
+      FROM_HERE, kTimeout,
+      base::BindOnce(&SyncedNetworkUpdaterImpl::OnError, base::Unretained(this),
+                     change_guid, id, kTimedOutErrorMsg));
+}
+
 }  // namespace sync_wifi
 
 }  // namespace chromeos
diff --git a/chromeos/components/sync_wifi/synced_network_updater_impl.h b/chromeos/components/sync_wifi/synced_network_updater_impl.h
index bf2034e..9114875 100644
--- a/chromeos/components/sync_wifi/synced_network_updater_impl.h
+++ b/chromeos/components/sync_wifi/synced_network_updater_impl.h
@@ -6,6 +6,7 @@
 #define CHROMEOS_COMPONENTS_SYNC_WIFI_SYNCED_NETWORK_UPDATER_IMPL_H_
 
 #include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
 #include "base/values.h"
 #include "chromeos/components/sync_wifi/network_identifier.h"
 #include "chromeos/components/sync_wifi/pending_network_configuration_tracker.h"
@@ -18,9 +19,11 @@
 
 namespace sync_wifi {
 
+class TimerFactory;
+
 // Implementation of SyncedNetworkUpdater. This class takes add/update/delete
 // requests from the sync backend and applies them to the local network stack
-// using chromeos::NetworkConfigurationHandler.
+// using mojom::CrosNetworkConfig.
 class SyncedNetworkUpdaterImpl
     : public SyncedNetworkUpdater,
       public chromeos::network_config::mojom::CrosNetworkConfigObserver {
@@ -28,7 +31,8 @@
   // |cros_network_config| must outlive this class.
   SyncedNetworkUpdaterImpl(
       std::unique_ptr<PendingNetworkConfigurationTracker> tracker,
-      network_config::mojom::CrosNetworkConfig* cros_network_config);
+      network_config::mojom::CrosNetworkConfig* cros_network_config,
+      std::unique_ptr<TimerFactory> timer_factory);
   ~SyncedNetworkUpdaterImpl() override;
 
   void AddOrUpdateNetwork(
@@ -50,9 +54,21 @@
   void OnNetworkCertificatesChanged() override {}
 
  private:
+  void StartAddOrUpdateOperation(
+      const std::string& change_guid,
+      const NetworkIdentifier& id,
+      const sync_pb::WifiConfigurationSpecificsData& specifics);
+  void StartDeleteOperation(const std::string& change_guid,
+                            const NetworkIdentifier& id,
+                            std::string guid);
+  void StartTimer(const std::string& change_guid, const NetworkIdentifier& id);
+  void Retry(const PendingNetworkConfigurationUpdate& update);
+  void HandleShillResult(const std::string& change_guid,
+                         const NetworkIdentifier& id,
+                         bool is_success);
   void CleanupUpdate(const std::string& change_guid,
                      const NetworkIdentifier& id);
-  network_config::mojom::NetworkStatePropertiesPtr FindLocalNetwork(
+  network_config::mojom::NetworkStatePropertiesPtr FindMojoNetwork(
       const NetworkIdentifier& id);
 
   base::Optional<base::DictionaryValue> ConvertToDictionary(
@@ -80,6 +96,9 @@
   mojo::Receiver<chromeos::network_config::mojom::CrosNetworkConfigObserver>
       cros_network_config_observer_receiver_{this};
   std::vector<network_config::mojom::NetworkStatePropertiesPtr> networks_;
+  std::unique_ptr<TimerFactory> timer_factory_;
+  base::flat_map<std::string, std::unique_ptr<base::OneShotTimer>>
+      change_guid_to_timer_map_;
 
   base::WeakPtrFactory<SyncedNetworkUpdaterImpl> weak_ptr_factory_{this};
 };
diff --git a/chromeos/components/sync_wifi/synced_network_updater_impl_unittest.cc b/chromeos/components/sync_wifi/synced_network_updater_impl_unittest.cc
index f2969dc4..34c0b1a5 100644
--- a/chromeos/components/sync_wifi/synced_network_updater_impl_unittest.cc
+++ b/chromeos/components/sync_wifi/synced_network_updater_impl_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
 #include "chromeos/components/sync_wifi/fake_pending_network_configuration_tracker.h"
+#include "chromeos/components/sync_wifi/fake_timer_factory.h"
 #include "chromeos/components/sync_wifi/network_identifier.h"
 #include "chromeos/components/sync_wifi/pending_network_configuration_tracker_impl.h"
 #include "chromeos/components/sync_wifi/synced_network_updater_impl.h"
@@ -134,9 +135,12 @@
 
     auto tracker_unique_ptr =
         std::make_unique<FakePendingNetworkConfigurationTracker>();
+    auto timer_factory_unique_ptr = std::make_unique<FakeTimerFactory>();
     tracker_ = tracker_unique_ptr.get();
+    timer_factory_ = timer_factory_unique_ptr.get();
     updater_ = std::make_unique<SyncedNetworkUpdaterImpl>(
-        std::move(tracker_unique_ptr), remote_cros_network_config_.get());
+        std::move(tracker_unique_ptr), remote_cros_network_config_.get(),
+        std::move(timer_factory_unique_ptr));
   }
 
   void TearDown() override {
@@ -145,6 +149,7 @@
   }
 
   FakePendingNetworkConfigurationTracker* tracker() { return tracker_; }
+  FakeTimerFactory* timer_factory() { return timer_factory_; }
   SyncedNetworkUpdaterImpl* updater() { return updater_.get(); }
   chromeos::NetworkStateTestHelper* network_state_helper() {
     return network_state_helper_.get();
@@ -154,6 +159,7 @@
 
  private:
   base::test::TaskEnvironment task_environment_;
+  FakeTimerFactory* timer_factory_;
   FakePendingNetworkConfigurationTracker* tracker_;
   std::unique_ptr<NetworkStateTestHelper> network_state_helper_;
   std::unique_ptr<SyncedNetworkUpdaterImpl> updater_;
@@ -223,7 +229,68 @@
   base::RunLoop().RunUntilIdle();
 
   EXPECT_FALSE(FindLocalNetworkById(fred_network_id()));
+
+  // The tracker should no longer be tracking the update because it reached the
+  // max failed number of attempts.
+  EXPECT_FALSE(tracker()->GetPendingUpdateById(fred_network_id()));
+  // Our test tracker holds on to the number of completed attempts after an
+  // update has been removed, and that should be equal to kMaxRetries (3).
+  EXPECT_EQ(3, tracker()->GetCompletedAttempts(fred_network_id()));
+}
+
+TEST_F(SyncedNetworkUpdaterImplTest, TestFailToAdd_Timeout) {
+  network_state_helper()->manager_test()->SetSimulateConfigurationResult(
+      chromeos::FakeShillSimulatedResult::kTimeout);
+
+  updater()->AddOrUpdateNetwork(GenerateTestWifiSpecifics(fred_network_id()));
   EXPECT_TRUE(tracker()->GetPendingUpdateById(fred_network_id()));
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(tracker()->GetPendingUpdateById(fred_network_id()));
+  EXPECT_EQ(0, tracker()->GetCompletedAttempts(fred_network_id()));
+
+  timer_factory()->FireAll();
+
+  EXPECT_TRUE(tracker()->GetPendingUpdateById(fred_network_id()));
+  EXPECT_EQ(1, tracker()->GetCompletedAttempts(fred_network_id()));
+
+  timer_factory()->FireAll();
+
+  EXPECT_TRUE(tracker()->GetPendingUpdateById(fred_network_id()));
+  EXPECT_EQ(2, tracker()->GetCompletedAttempts(fred_network_id()));
+
+  timer_factory()->FireAll();
+
+  EXPECT_EQ(3, tracker()->GetCompletedAttempts(fred_network_id()));
+  EXPECT_FALSE(tracker()->GetPendingUpdateById(fred_network_id()));
+}
+
+TEST_F(SyncedNetworkUpdaterImplTest, TestFailToAdd_Timeout_ThenSucceed) {
+  network_state_helper()->manager_test()->SetSimulateConfigurationResult(
+      chromeos::FakeShillSimulatedResult::kTimeout);
+
+  updater()->AddOrUpdateNetwork(GenerateTestWifiSpecifics(fred_network_id()));
+  EXPECT_TRUE(tracker()->GetPendingUpdateById(fred_network_id()));
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(tracker()->GetPendingUpdateById(fred_network_id()));
+  EXPECT_EQ(0, tracker()->GetCompletedAttempts(fred_network_id()));
+
+  timer_factory()->FireAll();
+
+  EXPECT_TRUE(tracker()->GetPendingUpdateById(fred_network_id()));
+  EXPECT_EQ(1, tracker()->GetCompletedAttempts(fred_network_id()));
+
+  network_state_helper()->manager_test()->SetSimulateConfigurationResult(
+      chromeos::FakeShillSimulatedResult::kSuccess);
+
+  timer_factory()->FireAll();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(tracker()->GetPendingUpdateById(fred_network_id()));
+  EXPECT_TRUE(FindLocalNetworkById(fred_network_id()));
 }
 
 TEST_F(SyncedNetworkUpdaterImplTest, TestFailToRemove) {
@@ -240,7 +307,8 @@
   base::RunLoop().RunUntilIdle();
 
   EXPECT_TRUE(FindLocalNetworkById(fred_network_id()));
-  EXPECT_TRUE(tracker()->GetPendingUpdateById(fred_network_id()));
+  EXPECT_FALSE(tracker()->GetPendingUpdateById(fred_network_id()));
+  EXPECT_EQ(3, tracker()->GetCompletedAttempts(fred_network_id()));
 }
 
 }  // namespace sync_wifi
diff --git a/chromeos/components/sync_wifi/timer_factory.cc b/chromeos/components/sync_wifi/timer_factory.cc
new file mode 100644
index 0000000..6ca7a8f
--- /dev/null
+++ b/chromeos/components/sync_wifi/timer_factory.cc
@@ -0,0 +1,21 @@
+// 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 "chromeos/components/sync_wifi/timer_factory.h"
+
+#include <memory>
+
+namespace chromeos {
+
+namespace sync_wifi {
+
+TimerFactory::~TimerFactory() = default;
+
+std::unique_ptr<base::OneShotTimer> TimerFactory::CreateOneShotTimer() {
+  return std::make_unique<base::OneShotTimer>();
+}
+
+}  // namespace sync_wifi
+
+}  // namespace chromeos
diff --git a/chromeos/components/sync_wifi/timer_factory.h b/chromeos/components/sync_wifi/timer_factory.h
new file mode 100644
index 0000000..43e7a4d
--- /dev/null
+++ b/chromeos/components/sync_wifi/timer_factory.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 CHROMEOS_COMPONENTS_SYNC_WIFI_TIMER_FACTORY_H_
+#define CHROMEOS_COMPONENTS_SYNC_WIFI_TIMER_FACTORY_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/timer/timer.h"
+
+namespace chromeos {
+
+namespace sync_wifi {
+
+// Serves as a simple Timer creator, injected into classes that use Timers.
+// Is intended to be overridden during testing in order to stub or mock the
+// Timers used by the object under test.
+class TimerFactory {
+ public:
+  virtual ~TimerFactory();
+
+  virtual std::unique_ptr<base::OneShotTimer> CreateOneShotTimer();
+};
+
+}  // namespace sync_wifi
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_SYNC_WIFI_TIMER_FACTORY_H_
diff --git a/chromeos/components/sync_wifi/wifi_configuration_sync_service.cc b/chromeos/components/sync_wifi/wifi_configuration_sync_service.cc
index 843551b6..62dacf6 100644
--- a/chromeos/components/sync_wifi/wifi_configuration_sync_service.cc
+++ b/chromeos/components/sync_wifi/wifi_configuration_sync_service.cc
@@ -11,6 +11,7 @@
 #include "base/time/default_clock.h"
 #include "chromeos/components/sync_wifi/pending_network_configuration_tracker_impl.h"
 #include "chromeos/components/sync_wifi/synced_network_updater_impl.h"
+#include "chromeos/components/sync_wifi/timer_factory.h"
 #include "chromeos/components/sync_wifi/wifi_configuration_bridge.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
 #include "components/sync/base/report_unrecoverable_error.h"
@@ -29,7 +30,7 @@
       remote_cros_network_config_.BindNewPipeAndPassReceiver());
   updater_ = std::make_unique<SyncedNetworkUpdaterImpl>(
       std::make_unique<PendingNetworkConfigurationTrackerImpl>(pref_service),
-      remote_cros_network_config_.get());
+      remote_cros_network_config_.get(), std::make_unique<TimerFactory>());
   bridge_ = std::make_unique<sync_wifi::WifiConfigurationBridge>(
       updater_.get(),
       std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
diff --git a/components/cronet/stale_host_resolver.cc b/components/cronet/stale_host_resolver.cc
index 5097042..58fb0c8 100644
--- a/components/cronet/stale_host_resolver.cc
+++ b/components/cronet/stale_host_resolver.cc
@@ -216,8 +216,10 @@
   cache_parameters.source = net::HostResolverSource::LOCAL_ONLY;
   cache_request_ = resolver_->inner_resolver_->CreateRequest(
       host_, network_isolation_key_, net_log_, cache_parameters);
-  cache_error_ =
+  int error =
       cache_request_->Start(base::BindOnce([](int error) { NOTREACHED(); }));
+  DCHECK_NE(net::ERR_IO_PENDING, error);
+  cache_error_ = cache_request_->GetResolveErrorInfo().error;
   DCHECK_NE(net::ERR_IO_PENDING, cache_error_);
   // If it's a fresh cache hit (or literal), return it synchronously.
   if (cache_error_ != net::ERR_DNS_CACHE_MISS &&
diff --git a/components/dom_distiller/core/javascript/dom_distiller_viewer.js b/components/dom_distiller/core/javascript/dom_distiller_viewer.js
index dee32ab..1c911d89 100644
--- a/components/dom_distiller/core/javascript/dom_distiller_viewer.js
+++ b/components/dom_distiller/core/javascript/dom_distiller_viewer.js
@@ -9,10 +9,18 @@
   distillerOnIos = false;
 }
 
+// The style guide recommends preferring $() to getElementById(). Chrome's
+// standard implementation of $() is imported from chrome://resources, which the
+// distilled page is prohibited from accessing. A version of it is
+// re-implemented here to allow stylistic consistency with other JS code.
+function $(id) {
+  return document.getElementById(id);
+}
+
 function addToPage(html) {
   const div = document.createElement('div');
   div.innerHTML = html;
-  document.getElementById('content').appendChild(div);
+  $('content').appendChild(div);
   fillYouTubePlaceholders();
 }
 
@@ -42,15 +50,12 @@
 }
 
 function showLoadingIndicator(isLastPage) {
-  document.getElementById('loading-indicator').className =
-      isLastPage ? 'hidden' : 'visible';
+  $('loading-indicator').className = isLastPage ? 'hidden' : 'visible';
 }
 
 // Sets the title.
 function setTitle(title) {
-  const holder = document.getElementById('title-holder');
-
-  holder.textContent = title;
+  $('title-holder').textContent = title;
   document.title = title;
 }
 
@@ -94,7 +99,7 @@
   } else {
     toolbarColor = '#F5F5F5';
   }
-  document.getElementById('theme-color').content = toolbarColor;
+  $('theme-color').content = toolbarColor;
 }
 
 function useFontScaling(scaling) {
@@ -161,8 +166,7 @@
 }
 
 const fontSizeSlider = new FontSizeSlider(
-    document.querySelector('#font-size-selection'),
-    [14, 15, 16, 18, 20, 24, 28, 32, 40, 48]);
+    $('font-size-selection'), [14, 15, 16, 18, 20, 24, 28, 32, 40, 48]);
 
 updateToolbarColor(getClassFromElement(document.body, themeClasses));
 maybeSetWebFont();
@@ -272,7 +276,7 @@
 
     this.restoreCenter_();
 
-    let img = document.getElementById('fontscaling-img');
+    let img = $('fontscaling-img');
     if (!img) {
       img = document.createElement('img');
       img.id = 'fontscaling-img';
@@ -432,9 +436,9 @@
 
 const pincher = new Pincher;
 
-document.querySelector('#settings-toggle').addEventListener('click', (e) => {
-  const dialog = document.querySelector('#settings-dialog');
-  const toggle = document.querySelector('#settings-toggle');
+$('settings-toggle').addEventListener('click', (e) => {
+  const dialog = $('settings-dialog');
+  const toggle = $('settings-toggle');
   if (dialog.open) {
     toggle.classList.remove('activated');
     dialog.close();
@@ -444,17 +448,15 @@
   }
 });
 
-document.querySelector('#close-settings-button')
-    .addEventListener('click', (e) => {
-      document.querySelector('#settings-toggle').classList.remove('activated');
-      document.querySelector('#settings-dialog').close();
-    });
+$('close-settings-button').addEventListener('click', (e) => {
+  $('settings-toggle').classList.remove('activated');
+  $('settings-dialog').close();
+});
 
-document.querySelector('#theme-selection').addEventListener('change', (e) => {
+$('theme-selection').addEventListener('change', (e) => {
   useTheme(e.target.value);
 });
 
-document.querySelector('#font-family-selection')
-    .addEventListener('change', (e) => {
-      useFontFamily(e.target.value);
-    });
+$('font-family-selection').addEventListener('change', (e) => {
+  useFontFamily(e.target.value);
+});
diff --git a/components/download/internal/common/download_item_impl.cc b/components/download/internal/common/download_item_impl.cc
index 2ae7841..2529294 100644
--- a/components/download/internal/common/download_item_impl.cc
+++ b/components/download/internal/common/download_item_impl.cc
@@ -970,7 +970,8 @@
           danger_type_ == DOWNLOAD_DANGER_TYPE_BLOCKED_TOO_LARGE ||
           danger_type_ == DOWNLOAD_DANGER_TYPE_BLOCKED_PASSWORD_PROTECTED ||
           danger_type_ == DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_BLOCK ||
-          danger_type_ == DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_WARNING);
+          danger_type_ == DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_WARNING ||
+          danger_type_ == DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING);
 }
 
 DownloadDangerType DownloadItemImpl::GetDangerType() const {
diff --git a/components/flags_ui/resources/flags.js b/components/flags_ui/resources/flags.js
index 68436ba..52595c3 100644
--- a/components/flags_ui/resources/flags.js
+++ b/components/flags_ui/resources/flags.js
@@ -328,6 +328,11 @@
  * @suppress {missingProperties}
  */
 function handleEnableExperimentalFeature(node, enable) {
+  /* This function is an onchange handler, which can be invoked during page
+   * restore - see https://crbug.com/1038638. */
+  if (!node.internal_name) {
+    return;
+  }
   chrome.send('enableExperimentalFeature', [String(node.internal_name),
                                             String(enable)]);
   experimentChangesUiUpdates(node, enable ? 1 : 0);
@@ -335,6 +340,11 @@
 
 /** @suppress {missingProperties} */
 function handleSetOriginListFlag(node, value) {
+  /* This function is an onchange handler, which can be invoked during page
+   * restore - see https://crbug.com/1038638. */
+  if (!node.internal_name) {
+    return;
+  }
   chrome.send('setOriginListFlag', [String(node.internal_name), String(value)]);
   showRestartToast(true);
 }
@@ -347,6 +357,11 @@
  * @suppress {missingProperties}
  */
 function handleSelectExperimentalFeatureChoice(node, index) {
+  /* This function is an onchange handler, which can be invoked during page
+   * restore - see https://crbug.com/1038638. */
+  if (!node.internal_name) {
+    return;
+  }
   chrome.send('enableExperimentalFeature',
               [String(node.internal_name) + '@' + index, 'true']);
   experimentChangesUiUpdates(node, index);
diff --git a/components/metrics/metrics_state_manager.cc b/components/metrics/metrics_state_manager.cc
index 70ee765..11434e279 100644
--- a/components/metrics/metrics_state_manager.cc
+++ b/components/metrics/metrics_state_manager.cc
@@ -139,15 +139,21 @@
       entropy_source_returned_(ENTROPY_SOURCE_NONE),
       metrics_ids_were_reset_(false) {
   ResetMetricsIDsIfNecessary();
+
+  bool is_first_run = false;
+  int64_t install_date = local_state_->GetInt64(prefs::kInstallDate);
+
+  // Set the install date if this is our first run.
+  if (install_date == 0) {
+    local_state_->SetInt64(prefs::kInstallDate, base::Time::Now().ToTimeT());
+    is_first_run = true;
+  }
+
   if (enabled_state_provider_->IsConsentGiven())
     ForceClientIdCreation();
 
-  // Set the install date if this is our first run.
-  int64_t install_date = local_state_->GetInt64(prefs::kInstallDate);
-  if (install_date == 0) {
-    local_state_->SetInt64(prefs::kInstallDate, base::Time::Now().ToTimeT());
-
 #if !defined(OS_WIN)
+  if (is_first_run) {
     // If this is a first run (no install date) and there's no client id, then
     // generate a provisional client id now. This id will be used for field
     // trial randomization on first run and will be promoted to become the
@@ -166,8 +172,8 @@
     // for this logic changes, the tests should be updated as well.
     if (client_id_.empty())
       provisional_client_id_ = base::GenerateGUID();
-#endif  // !defined(OS_WIN)
   }
+#endif  // !defined(OS_WIN)
 
   DCHECK(!instance_exists_);
   instance_exists_ = true;
diff --git a/components/metrics/metrics_state_manager_unittest.cc b/components/metrics/metrics_state_manager_unittest.cc
index 06c26821..98eeefb 100644
--- a/components/metrics/metrics_state_manager_unittest.cc
+++ b/components/metrics/metrics_state_manager_unittest.cc
@@ -367,6 +367,18 @@
   }
 }
 
+TEST_F(MetricsStateManagerTest,
+       ForceClientIdCreation_ConsentIntitially_NoInstallDate) {
+  // Confirm that the initial ForceClientIdCreation call creates the install
+  // date and then backs it up via MockStoreClientInfoBackup.
+  EXPECT_FALSE(stored_client_info_backup_);
+  EnableMetricsReporting();
+  std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
+
+  ASSERT_TRUE(stored_client_info_backup_);
+  EXPECT_NE(0, stored_client_info_backup_->installation_date);
+}
+
 #if !defined(OS_WIN)
 TEST_F(MetricsStateManagerTest, ProvisionalClientId_PromotedToClientId) {
   std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
diff --git a/components/omnibox/browser/autocomplete_result.cc b/components/omnibox/browser/autocomplete_result.cc
index 5fd774a..eb8b931 100644
--- a/components/omnibox/browser/autocomplete_result.cc
+++ b/components/omnibox/browser/autocomplete_result.cc
@@ -247,8 +247,7 @@
                                                  matches_, comparing_object);
   matches_.resize(num_matches);
 
-  if (OmniboxFieldTrial::IsGroupSuggestionsBySearchVsUrlFeatureEnabled() &&
-      matches_.size() > 2) {
+  if (matches_.size() > 2) {
     // Skip over default match.
     auto next = std::next(matches_.begin());
     // If it has submatches, skip them too.
@@ -487,23 +486,20 @@
 ACMatches::iterator AutocompleteResult::FindTopMatch(
     const AutocompleteInput& input,
     ACMatches* matches) {
-  // The matches may be sorted by type-demoted relevance. If we want to choose
-  // the highest-relevance, allowed-to-be-default match while ignoring type
-  // demotion, as we do when IsPreserveDefaultMatchScoreEnabled is true, we need
-  // to explicitly find the highest relevance match rather than just accepting
-  // the first allowed-to-be-default match in the list.
+  // The matches may be sorted by type-demoted relevance. We want to choose the
+  // highest-relevance, allowed-to-be-default match while ignoring type demotion
+  // in order to explicitly find the highest relevance match rather than just
+  // accepting the first allowed-to-be-default match in the list.
   // The goal of this behavior is to ensure that in situations where the user
   // expects to see a commonly visited URL as the default match, the URL is not
   // suppressed by type demotion.
-  // However, even if IsPreserveDefaultMatchScoreEnabled is true, we don't care
-  // about this URL behavior when the user is using the fakebox, which is
-  // intended to work more like a search-only box. Unless the user's input is a
-  // URL in which case we still want to ensure they can get a URL as the default
-  // match.
+  // However, we don't care about this URL behavior when the user is using the
+  // fakebox, which is intended to work more like a search-only box. Unless the
+  // user's input is a URL in which case we still want to ensure they can get a
+  // URL as the default match.
   if ((input.current_page_classification() !=
            OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS ||
-       input.type() == metrics::OmniboxInputType::URL) &&
-      OmniboxFieldTrial::IsPreserveDefaultMatchScoreEnabled()) {
+       input.type() == metrics::OmniboxInputType::URL)) {
     auto best = matches->end();
     for (auto it = matches->begin(); it != matches->end(); ++it) {
       if (it->allowed_to_be_default_match && !it->IsSubMatch() &&
diff --git a/components/omnibox/browser/autocomplete_result.h b/components/omnibox/browser/autocomplete_result.h
index e303f72..8f24cdd 100644
--- a/components/omnibox/browser/autocomplete_result.h
+++ b/components/omnibox/browser/autocomplete_result.h
@@ -100,8 +100,7 @@
   bool TopMatchIsStandaloneVerbatimMatch() const;
 
   // Returns the first match in |matches| which might be chosen as default.
-  // If |kOmniboxPreserveDefaultMatchScore| is enabled and the page is not
-  // the fake box, the scores are not demoted by type.
+  // If the page is not the fake box, the scores are not demoted by type.
   static ACMatches::const_iterator FindTopMatch(const AutocompleteInput& input,
                                                 const ACMatches& matches);
   static ACMatches::iterator FindTopMatch(const AutocompleteInput& input,
diff --git a/components/omnibox/browser/autocomplete_result_unittest.cc b/components/omnibox/browser/autocomplete_result_unittest.cc
index ff41b15..cf45a40 100644
--- a/components/omnibox/browser/autocomplete_result_unittest.cc
+++ b/components/omnibox/browser/autocomplete_result_unittest.cc
@@ -35,12 +35,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/metrics_proto/omnibox_event.pb.h"
 
-#if defined(OS_IOS) || defined(OS_ANDROID)
-#define MOBILE_DISABLED(name) DISABLED_##name
-#else
-#define MOBILE_DISABLED(name) name
-#endif
-
 using metrics::OmniboxEventProto;
 
 namespace {
@@ -776,59 +770,6 @@
 }
 
 TEST_F(AutocompleteResultTest, SortAndCullWithDemotionsByType) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures({},
-                                {omnibox::kOmniboxGroupSuggestionsBySearchVsUrl,
-                                 omnibox::kOmniboxPreserveDefaultMatchScore});
-
-  // Add some matches.
-  ACMatches matches;
-  const AutocompleteMatchTestData data[] = {
-      {"http://history-url/", AutocompleteMatchType::HISTORY_URL},
-      {"http://search-what-you-typed/",
-       AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
-      {"http://history-title/", AutocompleteMatchType::HISTORY_TITLE},
-      {"http://search-history/", AutocompleteMatchType::SEARCH_HISTORY},
-  };
-  PopulateAutocompleteMatchesFromTestData(data, base::size(data), &matches);
-
-  // Demote the search history match relevance score.
-  matches.back().relevance = 500;
-
-  // Add a rule demoting history-url and killing history-title.
-  {
-    std::map<std::string, std::string> params;
-    params[std::string(OmniboxFieldTrial::kDemoteByTypeRule) + ":3:*"] =
-        "1:50,7:100,2:0";  // 3 == HOME_PAGE
-    ASSERT_TRUE(variations::AssociateVariationParams(
-        OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params));
-  }
-  base::FieldTrialList::CreateFieldTrial(
-      OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
-
-  AutocompleteInput input(base::ASCIIToUTF16("a"), OmniboxEventProto::HOME_PAGE,
-                          TestSchemeClassifier());
-  AutocompleteResult result;
-  result.AppendMatches(input, matches);
-  result.SortAndCull(input, template_url_service_.get());
-
-  // Check the new ordering.  The history-title results should be omitted.
-  size_t expected_order[] = {1, 0, 3};
-  ASSERT_EQ(base::size(expected_order), result.size());
-  for (size_t i = 0; i < base::size(expected_order); ++i) {
-    EXPECT_EQ(data[expected_order[i]].destination_url,
-              result.match_at(i)->destination_url.spec());
-  }
-}
-
-TEST_F(AutocompleteResultTest,
-       MOBILE_DISABLED(
-           SortAndCullWithDemotionsByTypeWithPreserveAndGroupingFeatures)) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures({omnibox::kOmniboxGroupSuggestionsBySearchVsUrl,
-                                 omnibox::kOmniboxPreserveDefaultMatchScore},
-                                {});
-
   // Add some matches.
   ACMatches matches;
   const AutocompleteMatchTestData data[] = {
@@ -861,8 +802,8 @@
   result.SortAndCull(input, template_url_service_.get());
 
   // Check the new ordering.  The history-title results should be omitted.
-  // HistoryURL should still be first despite demotion because of the
-  // OmniboxPreserveDefaultMatchScore feature.
+  // HistoryURL should still be first because type demotion is not applied to
+  // the top match.
   size_t expected_order[] = {0, 1, 3};
 
   ASSERT_EQ(base::size(expected_order), result.size());
@@ -1072,12 +1013,7 @@
   }
 }
 
-TEST_F(AutocompleteResultTest, DemoteByTypeButPreserveDefaultMatchScore) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      {omnibox::kOmniboxPreserveDefaultMatchScore},
-      {omnibox::kOmniboxGroupSuggestionsBySearchVsUrl});
-
+TEST_F(AutocompleteResultTest, DemoteByType) {
   // Add some matches.
   ACMatches matches;
   const AutocompleteMatchTestData data[] = {
@@ -1112,103 +1048,11 @@
     result.AppendMatches(input, matches);
     result.SortAndCull(input, template_url_service_.get());
 
-    // Make sure history-title is the default match, despite demotion.
-    size_t expected_order[] = {1, 0, 2, 3};
-
-    ASSERT_EQ(base::size(expected_order), result.size());
-    for (size_t i = 0; i < base::size(expected_order); ++i) {
-      EXPECT_EQ(data[expected_order[i]].destination_url,
-                result.match_at(i)->destination_url.spec());
-    }
-  }
-
-  {
-    // Re-sort with a page classification of fake-box, and make sure
-    // history-title is now demoted.
-    AutocompleteInput input(
-        base::ASCIIToUTF16("a"),
-        OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS,
-        TestSchemeClassifier());
-    AutocompleteResult result;
-    result.AppendMatches(input, matches);
-    result.SortAndCull(input, template_url_service_.get());
-
-    size_t expected_order[] = {3, 0, 2, 1};
-
-    ASSERT_EQ(base::size(expected_order), result.size());
-    for (size_t i = 0; i < base::size(expected_order); ++i) {
-      EXPECT_EQ(data[expected_order[i]].destination_url,
-                result.match_at(i)->destination_url.spec());
-    }
-  }
-
-  {
-    // Re-sort with a page classification of fake-box and an input that's a URL,
-    // and make sure history-title is once again the default match.
-    AutocompleteInput input(
-        base::ASCIIToUTF16("www.example.com"),
-        OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS,
-        TestSchemeClassifier());
-    AutocompleteResult result;
-    result.AppendMatches(input, matches);
-    result.SortAndCull(input, template_url_service_.get());
-
-    size_t expected_order[] = {1, 0, 2, 3};
-
-    ASSERT_EQ(base::size(expected_order), result.size());
-    for (size_t i = 0; i < base::size(expected_order); ++i) {
-      EXPECT_EQ(data[expected_order[i]].destination_url,
-                result.match_at(i)->destination_url.spec());
-    }
-  }
-}
-
-TEST_F(
-    AutocompleteResultTest,
-    MOBILE_DISABLED(
-        DemoteByTypeButPreserveDefaultMatchScoreWithPreserveAndGroupingFeatures)) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures({omnibox::kOmniboxGroupSuggestionsBySearchVsUrl,
-                                 omnibox::kOmniboxPreserveDefaultMatchScore},
-                                {});
-
-  // Add some matches.
-  ACMatches matches;
-  const AutocompleteMatchTestData data[] = {
-      {"http://history-url/", AutocompleteMatchType::HISTORY_URL},
-      {"http://history-title/", AutocompleteMatchType::HISTORY_TITLE},
-      {"http://search-what-you-typed/",
-       AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
-      {"http://search-history/", AutocompleteMatchType::SEARCH_HISTORY},
-  };
-  PopulateAutocompleteMatchesFromTestData(data, base::size(data), &matches);
-
-  // Make history-title and search-history the only default matches, so that
-  // they compete.
-  matches[0].allowed_to_be_default_match = false;
-  matches[2].allowed_to_be_default_match = false;
-
-  // Add a rule demoting history-title.
-  {
-    std::map<std::string, std::string> params;
-    params[std::string(OmniboxFieldTrial::kDemoteByTypeRule) + ":*:*"] = "2:50";
-    ASSERT_TRUE(variations::AssociateVariationParams(
-        OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params));
-  }
-  base::FieldTrialList::CreateFieldTrial(
-      OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
-
-  {
-    AutocompleteInput input(base::ASCIIToUTF16("a"),
-                            OmniboxEventProto::HOME_PAGE,
-                            TestSchemeClassifier());
-    AutocompleteResult result;
-    result.AppendMatches(input, matches);
-    result.SortAndCull(input, template_url_service_.get());
-
-    // Make sure history-title is the default match, despite demotion.
-    // Make sure history-URL is the last match due to
-    // OmniboxGroupSuggestionsBySearchVsUrl.
+    // Because we want to ensure the highest naturally scoring
+    // allowed-to-be default suggestion is the default, make sure history-title
+    // is the default match despite demotion.
+    // Make sure history-URL is the last match due to the logic which groups
+    // searches and URLs together.
     size_t expected_order[] = {1, 2, 3, 0};
 
     ASSERT_EQ(base::size(expected_order), result.size());
@@ -1219,8 +1063,11 @@
   }
 
   {
-    // Re-sort with a page classification of fake-box, and make sure
-    // history-title is now demoted.
+    // However, in the fakebox, we do want to use the demoted score when
+    // selecting the default match because we generally only expect it to be
+    // used for queries and we demote URLs strongly. So here we re-sort with a
+    // page classification of fake-box, and make sure history-title is now
+    // demoted.
     AutocompleteInput input(
         base::ASCIIToUTF16("a"),
         OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS,
@@ -1229,8 +1076,8 @@
     result.AppendMatches(input, matches);
     result.SortAndCull(input, template_url_service_.get());
 
-    // Make sure history-URL is the last match due to
-    // OmniboxGroupSuggestionsBySearchVsUrl.
+    // Make sure history-URL is the last match due to the logic which groups
+    // searches and URLs together.
     size_t expected_order[] = {3, 2, 0, 1};
 
     ASSERT_EQ(base::size(expected_order), result.size());
@@ -1239,6 +1086,29 @@
                 result.match_at(i)->destination_url.spec());
     }
   }
+
+  {
+    // Unless, the user's input looks like a URL, in which case we want to use
+    // the natural scoring again to make sure the user gets a URL if they're
+    // clearly trying to navigate. So here we re-sort with a page classification
+    // of fake-box and an input that's a URL, and make sure history-title is
+    // once again the default match.
+    AutocompleteInput input(
+        base::ASCIIToUTF16("www.example.com"),
+        OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS,
+        TestSchemeClassifier());
+    AutocompleteResult result;
+    result.AppendMatches(input, matches);
+    result.SortAndCull(input, template_url_service_.get());
+
+    size_t expected_order[] = {1, 2, 3, 0};
+
+    ASSERT_EQ(base::size(expected_order), result.size());
+    for (size_t i = 0; i < base::size(expected_order); ++i) {
+      EXPECT_EQ(data[expected_order[i]].destination_url,
+                result.match_at(i)->destination_url.spec());
+    }
+  }
 }
 
 TEST_F(AutocompleteResultTest, SortAndCullReorderForDefaultMatch) {
@@ -1560,11 +1430,8 @@
 TEST_F(AutocompleteResultTest, SortAndCullGroupSuggestionsByType) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeaturesAndParameters(
-      {
-          {omnibox::kUIExperimentMaxAutocompleteMatches,
-           {{OmniboxFieldTrial::kUIMaxAutocompleteMatchesParam, "6"}}},
-          {omnibox::kOmniboxGroupSuggestionsBySearchVsUrl, {/* no params */}},
-      },
+      {{omnibox::kUIExperimentMaxAutocompleteMatches,
+        {{OmniboxFieldTrial::kUIMaxAutocompleteMatchesParam, "6"}}}},
       {/* nothing disabled */});
   TestData data[] = {
     { 0, 1,  500, false },
@@ -1613,96 +1480,6 @@
         {{OmniboxFieldTrial::kUIMaxAutocompleteMatchesParam, "6"}}},
        {omnibox::kOmniboxMaxURLMatches,
         {{OmniboxFieldTrial::kOmniboxMaxURLMatchesParam, "3"}}}},
-      {omnibox::kOmniboxGroupSuggestionsBySearchVsUrl,
-       omnibox::kOmniboxPreserveDefaultMatchScore});
-
-  EXPECT_TRUE(OmniboxFieldTrial::IsMaxURLMatchesFeatureEnabled());
-  EXPECT_EQ(OmniboxFieldTrial::GetMaxURLMatches(), 3u);
-
-  // Case 1: Eject URL match for a search.
-  {
-    ACMatches matches;
-    const AutocompleteMatchTestData data[] = {
-        {"http://search-what-you-typed/",
-         AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
-        {"http://search-history/", AutocompleteMatchType::SEARCH_HISTORY},
-        {"http://history-url/", AutocompleteMatchType::HISTORY_URL},
-        {"http://history-title/", AutocompleteMatchType::HISTORY_TITLE},
-        {"http://url-what-you-typed/",
-         AutocompleteMatchType::URL_WHAT_YOU_TYPED},
-        {"http://clipboard-url/", AutocompleteMatchType::CLIPBOARD_URL},
-        {"http://search-suggest/", AutocompleteMatchType::SEARCH_SUGGEST},
-    };
-    PopulateAutocompleteMatchesFromTestData(data, base::size(data), &matches);
-
-    AutocompleteInput input(base::ASCIIToUTF16("a"),
-                            metrics::OmniboxEventProto::OTHER,
-                            TestSchemeClassifier());
-    AutocompleteResult result;
-    result.AppendMatches(input, matches);
-    result.SortAndCull(input, template_url_service_.get());
-
-    AutocompleteMatchType::Type expected_types[] = {
-        AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
-        AutocompleteMatchType::SEARCH_HISTORY,
-        AutocompleteMatchType::HISTORY_URL,
-        AutocompleteMatchType::HISTORY_TITLE,
-        AutocompleteMatchType::URL_WHAT_YOU_TYPED,
-        AutocompleteMatchType::SEARCH_SUGGEST,
-    };
-    EXPECT_EQ(result.size(), AutocompleteResult::GetMaxMatches());
-    for (size_t i = 0; i < result.size(); ++i)
-      EXPECT_EQ(result.match_at(i)->type, expected_types[i]);
-  }
-
-  // Case 2: Do not eject URL match because there's no replacement.
-  {
-    ACMatches matches;
-    const AutocompleteMatchTestData data[] = {
-        {"http://search-what-you-typed/",
-         AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
-        {"http://search-history/", AutocompleteMatchType::SEARCH_HISTORY},
-        {"http://history-url/", AutocompleteMatchType::HISTORY_URL},
-        {"http://history-title/", AutocompleteMatchType::HISTORY_TITLE},
-        {"http://url-what-you-typed/",
-         AutocompleteMatchType::URL_WHAT_YOU_TYPED},
-        {"http://clipboard-url/", AutocompleteMatchType::CLIPBOARD_URL},
-        {"http://bookmark-title/", AutocompleteMatchType::BOOKMARK_TITLE},
-    };
-    PopulateAutocompleteMatchesFromTestData(data, base::size(data), &matches);
-
-    AutocompleteInput input(base::ASCIIToUTF16("a"),
-                            metrics::OmniboxEventProto::OTHER,
-                            TestSchemeClassifier());
-    AutocompleteResult result;
-    result.AppendMatches(input, matches);
-    result.SortAndCull(input, template_url_service_.get());
-
-    EXPECT_EQ(result.size(), AutocompleteResult::GetMaxMatches());
-    AutocompleteMatchType::Type expected_types[] = {
-        AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
-        AutocompleteMatchType::SEARCH_HISTORY,
-        AutocompleteMatchType::HISTORY_URL,
-        AutocompleteMatchType::HISTORY_TITLE,
-        AutocompleteMatchType::URL_WHAT_YOU_TYPED,
-        AutocompleteMatchType::CLIPBOARD_URL,
-    };
-    for (size_t i = 0; i < result.size(); ++i)
-      EXPECT_EQ(result.match_at(i)->type, expected_types[i]);
-  }
-}
-
-TEST_F(
-    AutocompleteResultTest,
-    MOBILE_DISABLED(SortAndCullMaxURLMatchesWithPreserveAndGroupingFeatures)) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeaturesAndParameters(
-      {{omnibox::kUIExperimentMaxAutocompleteMatches,
-        {{OmniboxFieldTrial::kUIMaxAutocompleteMatchesParam, "6"}}},
-       {omnibox::kOmniboxMaxURLMatches,
-        {{OmniboxFieldTrial::kOmniboxMaxURLMatchesParam, "3"}}},
-       {omnibox::kOmniboxGroupSuggestionsBySearchVsUrl, {}},
-       {omnibox::kOmniboxPreserveDefaultMatchScore, {}}},
       {});
 
   EXPECT_TRUE(OmniboxFieldTrial::IsMaxURLMatchesFeatureEnabled());
@@ -1732,7 +1509,7 @@
     result.SortAndCull(input, template_url_service_.get());
 
     // Expect the search suggest to be moved about URL suggestions due to
-    // OmniboxGroupSuggestionsBySearchVsUrl.
+    // the logic which groups searches and URLs together.
     AutocompleteMatchType::Type expected_types[] = {
         AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
         AutocompleteMatchType::SEARCH_HISTORY,
@@ -2105,12 +1882,6 @@
 }
 
 TEST_F(AutocompleteResultTest, SortAndCullWithDemotedSubmatches) {
-  base::test::ScopedFeatureList feature_list;
-  // Disable overriding features to only test standard sorting.
-  feature_list.InitWithFeatures({},
-                                {omnibox::kOmniboxGroupSuggestionsBySearchVsUrl,
-                                 omnibox::kOmniboxPreserveDefaultMatchScore});
-
   ACMatches matches;
   const AutocompleteMatchTestData data[] = {
       {"http://history-url/", AutocompleteMatchType::HISTORY_URL},
@@ -2155,15 +1926,15 @@
   // the demoted history-url match, and the history-title results and
   // its submatch should be omitted.
   ASSERT_EQ(4u, result.size());
-  EXPECT_EQ(result.match_at(0)->destination_url.spec(),
-            "http://search-what-you-typed/");
+  EXPECT_EQ(result.match_at(0)->destination_url.spec(), "http://history-url/");
   EXPECT_EQ(result.match_at(1)->destination_url.spec(),
-            "http://search-history/");
-  EXPECT_EQ(result.match_at(2)->destination_url.spec(), "http://history-url/");
-  EXPECT_EQ(result.match_at(3)->destination_url.spec(),
             "http://search-history-submatch1/");
+  EXPECT_EQ(result.match_at(2)->destination_url.spec(),
+            "http://search-what-you-typed/");
+  EXPECT_EQ(result.match_at(3)->destination_url.spec(),
+            "http://search-history/");
   EXPECT_TRUE(AutocompleteMatch::IsSameFamily(
-      result.match_at(2)->subrelevance, result.match_at(3)->subrelevance));
+      result.match_at(0)->subrelevance, result.match_at(1)->subrelevance));
 }
 
 TEST_F(AutocompleteResultTest, CalculateNumMatchesTest) {
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index 7a0b98a..7f56747 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -640,11 +640,6 @@
       OmniboxFieldTrial::kOmniboxMaxURLMatchesParam, kDefaultMaxURLMatches);
 }
 
-bool OmniboxFieldTrial::IsPreserveDefaultMatchScoreEnabled() {
-  return base::FeatureList::IsEnabled(
-      omnibox::kOmniboxPreserveDefaultMatchScore);
-}
-
 bool OmniboxFieldTrial::IsReverseAnswersEnabled() {
   return base::FeatureList::IsEnabled(omnibox::kOmniboxReverseAnswers);
 }
@@ -686,11 +681,6 @@
   return base::FeatureList::IsEnabled(omnibox::kExperimentalKeywordMode);
 }
 
-bool OmniboxFieldTrial::IsGroupSuggestionsBySearchVsUrlFeatureEnabled() {
-  return base::FeatureList::IsEnabled(
-      omnibox::kOmniboxGroupSuggestionsBySearchVsUrl);
-}
-
 bool OmniboxFieldTrial::IsMaxURLMatchesFeatureEnabled() {
   return base::FeatureList::IsEnabled(omnibox::kOmniboxMaxURLMatches);
 }
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h
index b7a61e5..32c32b8 100644
--- a/components/omnibox/browser/omnibox_field_trial.h
+++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -377,9 +377,6 @@
 // ---------------------------------------------------------
 // For UI experiments.
 
-// Returns whether preserve default match score is enabled.
-bool IsPreserveDefaultMatchScoreEnabled();
-
 // Returns true if the reverse answers flag is enabled.
 bool IsReverseAnswersEnabled();
 
@@ -410,10 +407,6 @@
 // assortment of keyword mode experiments.
 bool IsExperimentalKeywordModeEnabled();
 
-// Returns whether the group suggestions by type feature is enabled,
-// which "bunches" search suggestions (except for the default match).
-bool IsGroupSuggestionsBySearchVsUrlFeatureEnabled();
-
 // Returns whether the feature to limit the number of shown URL matches
 // is enabled.
 bool IsMaxURLMatchesFeatureEnabled();
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index e08b550..47360011 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -55,12 +55,6 @@
 const base::Feature kSimplifyHttpsIndicator{"SimplifyHttpsIndicator",
                                             base::FEATURE_ENABLED_BY_DEFAULT};
 
-// This feature is used to have final suggestions within the Omnibox grouped
-// by major type. i.e. search types are first, followed by all others,
-// except for the default match which is unchanged in position.
-const base::Feature kOmniboxGroupSuggestionsBySearchVsUrl{
-    "OmniboxGroupSuggestionsBySearchVsUrl", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Feature used to enable local entity suggestions. Similar to rich entities but
 // but location specific. E.g., typing 'starbucks near' could display the local
 // entity suggestion 'starbucks near disneyland \n starbucks * Anaheim, CA'.
@@ -258,10 +252,6 @@
 const base::Feature kDebounceDocumentProvider{
     "OmniboxDebounceDocumentProvider", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Exempts the default match from demotion-by-type.
-const base::Feature kOmniboxPreserveDefaultMatchScore{
-    "OmniboxPreserveDefaultMatchScore", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Preserves the default match against change when providers return results
 // asynchronously. This prevents the default match from changing after the user
 // finishes typing. Without this feature, if the default match is updated right
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h
index 4865db3..ff75b43 100644
--- a/components/omnibox/common/omnibox_features.h
+++ b/components/omnibox/common/omnibox_features.h
@@ -18,7 +18,6 @@
 extern const base::Feature kHideSteadyStateUrlPathQueryAndRef;
 extern const base::Feature kOneClickUnelide;
 extern const base::Feature kSimplifyHttpsIndicator;
-extern const base::Feature kOmniboxGroupSuggestionsBySearchVsUrl;
 extern const base::Feature kOmniboxLocalEntitySuggestions;
 extern const base::Feature kOmniboxMaxURLMatches;
 extern const base::Feature kOmniboxRichEntitySuggestions;
@@ -50,7 +49,6 @@
 
 // Flags that affect the "twiddle" step of AutocompleteResult, i.e. SortAndCull.
 // TODO(tommycli): There are more flags above that belong in this category.
-extern const base::Feature kOmniboxPreserveDefaultMatchScore;
 extern const base::Feature kOmniboxPreserveDefaultMatchAgainstAsyncUpdate;
 extern const base::Feature kOmniboxDemoteByType;
 
diff --git a/components/os_crypt/os_crypt_win.cc b/components/os_crypt/os_crypt_win.cc
index 8a7f33e7..67b8339 100644
--- a/components/os_crypt/os_crypt_win.cc
+++ b/components/os_crypt/os_crypt_win.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/os_crypt/os_crypt.h"
-
 #include <windows.h>
 
 #include "base/base64.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/no_destructor.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/wincrypt_shim.h"
+#include "components/os_crypt/os_crypt.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "crypto/aead.h"
@@ -58,8 +58,8 @@
 bool EncryptStringWithDPAPI(const std::string& plaintext,
                             std::string* ciphertext) {
   DATA_BLOB input;
-  input.pbData = const_cast<BYTE*>(
-      reinterpret_cast<const BYTE*>(plaintext.data()));
+  input.pbData =
+      const_cast<BYTE*>(reinterpret_cast<const BYTE*>(plaintext.data()));
   input.cbData = static_cast<DWORD>(plaintext.length());
 
   DATA_BLOB output;
@@ -81,8 +81,8 @@
 bool DecryptStringWithDPAPI(const std::string& ciphertext,
                             std::string* plaintext) {
   DATA_BLOB input;
-  input.pbData = const_cast<BYTE*>(
-      reinterpret_cast<const BYTE*>(ciphertext.data()));
+  input.pbData =
+      const_cast<BYTE*>(reinterpret_cast<const BYTE*>(ciphertext.data()));
   input.cbData = static_cast<DWORD>(ciphertext.length());
 
   DATA_BLOB output;
@@ -203,13 +203,18 @@
     std::string encrypted_key =
         encrypted_key_with_header.substr(sizeof(kDPAPIKeyPrefix) - 1);
     std::string key;
-    if (!DecryptStringWithDPAPI(encrypted_key, &key))
-      return false;
-    GetEncryptionKeyFactory().assign(key);
-    return true;
+    // This DPAPI decryption can fail if the user's password has been reset
+    // by an Administrator.
+    if (DecryptStringWithDPAPI(encrypted_key, &key)) {
+      GetEncryptionKeyFactory().assign(key);
+      return true;
+    }
+    base::UmaHistogramSparse("OSCrypt.Win.KeyDecryptionError",
+                             ::GetLastError());
   }
 
-  // Otherwise, generate a key.
+  // If there is no key in the local state, or if DPAPI decryption fails,
+  // generate a new key.
   std::string key;
 
   crypto::RandBytes(base::WriteInto(&key, kKeyLength + 1), kKeyLength);
diff --git a/components/resources/BUILD.gn b/components/resources/BUILD.gn
index 31d3b78d..d8e7ea1 100644
--- a/components/resources/BUILD.gn
+++ b/components/resources/BUILD.gn
@@ -12,6 +12,7 @@
   public_deps = [
     ":components_resources",
     ":components_scaled_resources",
+    ":dev_ui_components_resources",
   ]
 }
 
@@ -44,6 +45,16 @@
   ]
 }
 
+grit("dev_ui_components_resources") {
+  source = "dev_ui_components_resources.grd"
+
+  outputs = [
+    "grit/dev_ui_components_resources.h",
+    "dev_ui_components_resources.pak",
+  ]
+  output_dir = "$root_gen_dir/components"
+}
+
 grit("components_scaled_resources") {
   source = "components_scaled_resources.grd"
 
diff --git a/components/resources/OWNERS b/components/resources/OWNERS
index 2e7f98ef..a04e915 100644
--- a/components/resources/OWNERS
+++ b/components/resources/OWNERS
@@ -18,12 +18,14 @@
 per-file gcm_driver_resources.grdp=zea@chromium.org
 per-file neterror*=mmenke@chromium.org
 per-file neterror*=file://net/OWNERS
+per-file ntp_tiles_dev_ui_resources.grdp=file://components/ntp_tiles/OWNERS
 per-file ntp_tiles_resources.grdp=file://components/ntp_tiles/OWNERS
 per-file welcome_scaled_resources.grdp=file://ui/webui/PLATFORM_OWNERS
 per-file offline_pages_resources.grdp=file://components/offline_pages/OWNERS
 per-file policy_resources.grdp=file://components/policy/OWNERS
 per-file proximity_auth*=tengs@chromium.org
 per-file printing_resources.grdp=file://printing/OWNERS
+per-file security_interstitials_dev_ui_resources.grdp=file://components/security_interstitials/OWNERS
 per-file security_interstitials_resources.grdp=file://components/security_interstitials/OWNERS
 per-file sync_driver_resources.grdp=file://components/sync/OWNERS
 per-file translate_resources.grdp=file://components/translate/OWNERS
diff --git a/components/resources/components_resources.grd b/components/resources/components_resources.grd
index b0ad24b..9edac3d 100644
--- a/components/resources/components_resources.grd
+++ b/components/resources/components_resources.grd
@@ -1,4 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!--
+This file aggregates resource GRDPs for user-facing features under /components.
+Resources for developer-facing chrome:// pages should be aggregated in
+dev_ui_components_resources.grd.
+-->
 <grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
   <outputs>
     <output filename="grit/components_resources.h" type="rc_header">
@@ -8,23 +13,16 @@
   </outputs>
   <release seq="1">
     <includes>
-      <part file="autofill_and_password_manager_internals_resources.grdp" />
       <part file="about_ui_resources.grdp" />
-      <part file="crash_resources.grdp" />
       <part file="dom_distiller_resources.grdp" />
       <part file="flags_ui_resources.grdp" />
-      <part file="gcm_driver_resources.grdp" />
-      <part file="net_log_resources.grdp" />
       <part file="neterror_resources.grdp" />
       <part file="ntp_tiles_resources.grdp" />
       <part file="offline_pages_resources.grdp" />
-      <part file="policy_resources.grdp" />
       <part file="printing_resources.grdp" />
       <part file="safe_browsing_resources.grdp" />
       <part file="security_interstitials_resources.grdp" />
-      <part file="signin_resources.grdp" />
       <part file="translate_resources.grdp" />
-      <part file="user_actions_ui_resources.grdp" />
       <part file="version_ui_resources.grdp" />
     </includes>
   </release>
diff --git a/components/resources/dev_ui_components_resources.grd b/components/resources/dev_ui_components_resources.grd
new file mode 100644
index 0000000..8eb7db9
--- /dev/null
+++ b/components/resources/dev_ui_components_resources.grd
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+This file aggregates resource GRDPs for developer-facing chrome:// pages
+(DevUI pages) under /components. This is needed by the Developer WebUI Dynamic
+Feature Module (DevUI DFM) for Android Chrome. More info:
+* User-facing resources should be aggregated in component_resources.grd.
+* DevUI page resources that are *not* for Android Chrome can be aggregated in
+  component_resources.grd (or browser_resources.grd if applicable).
+-->
+<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
+  <outputs>
+    <output filename="grit/dev_ui_components_resources.h" type="rc_header">
+      <emit emit_type='prepend'></emit>
+    </output>
+    <output filename="dev_ui_components_resources.pak" type="data_package" />
+  </outputs>
+  <release seq="1">
+    <includes>
+      <part file="autofill_and_password_manager_internals_resources.grdp" />
+      <part file="crash_resources.grdp" />
+      <part file="gcm_driver_resources.grdp" />
+      <part file="net_log_resources.grdp" />
+      <part file="ntp_tiles_dev_ui_resources.grdp" />
+      <part file="policy_resources.grdp" />
+      <part file="security_interstitials_dev_ui_resources.grdp" />
+      <part file="signin_resources.grdp" />
+      <part file="user_actions_ui_resources.grdp" />
+    </includes>
+  </release>
+</grit>
diff --git a/components/resources/ntp_tiles_dev_ui_resources.grdp b/components/resources/ntp_tiles_dev_ui_resources.grdp
new file mode 100644
index 0000000..93ee50f
--- /dev/null
+++ b/components/resources/ntp_tiles_dev_ui_resources.grdp
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Resources for developer-facing page chrome://ntp-tiles-internals. -->
+<grit-part>
+  <include name="IDR_NTP_TILES_INTERNALS_HTML"
+           file="../ntp_tiles/webui/resources/ntp_tiles_internals.html"
+           flattenhtml="true"
+           allowexternalscript="true"
+           type="BINDATA"
+           compress="gzip" />
+  <include name="IDR_NTP_TILES_INTERNALS_JS"
+           file="../ntp_tiles/webui/resources/ntp_tiles_internals.js"
+           type="BINDATA"
+           compress="gzip" />
+  <include name="IDR_NTP_TILES_INTERNALS_CSS"
+           file="../ntp_tiles/webui/resources/ntp_tiles_internals.css"
+           type="BINDATA"
+           compress="gzip" />
+</grit-part>
diff --git a/components/resources/ntp_tiles_resources.grdp b/components/resources/ntp_tiles_resources.grdp
index cace33e3..cca535d 100644
--- a/components/resources/ntp_tiles_resources.grdp
+++ b/components/resources/ntp_tiles_resources.grdp
@@ -1,4 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!-- Resources for user-facing NTP features. -->
 <grit-part>
   <if expr="is_android or is_ios">
     <if expr="_google_chrome">
@@ -19,7 +20,4 @@
       </else>
     </if>
   </if>
-  <include name="IDR_NTP_TILES_INTERNALS_HTML" file="../ntp_tiles/webui/resources/ntp_tiles_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" />
-  <include name="IDR_NTP_TILES_INTERNALS_JS" file="../ntp_tiles/webui/resources/ntp_tiles_internals.js" type="BINDATA" compress="gzip" />
-  <include name="IDR_NTP_TILES_INTERNALS_CSS" file="../ntp_tiles/webui/resources/ntp_tiles_internals.css" type="BINDATA" compress="gzip" />
 </grit-part>
diff --git a/components/resources/security_interstitials_dev_ui_resources.grdp b/components/resources/security_interstitials_dev_ui_resources.grdp
new file mode 100644
index 0000000..d15f1f8
--- /dev/null
+++ b/components/resources/security_interstitials_dev_ui_resources.grdp
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Resources for developer-facing page chrome://interstitials. -->
+<grit-part>
+  <include name="IDR_SECURITY_INTERSTITIAL_UI_HTML"
+           file="../security_interstitials/core/browser/resources/list_of_interstitials.html"
+           compress="gzip"
+           flattenhtml="true"
+           type="BINDATA" />
+</grit-part>
diff --git a/components/resources/security_interstitials_resources.grdp b/components/resources/security_interstitials_resources.grdp
index d7fb468..8cbde16 100644
--- a/components/resources/security_interstitials_resources.grdp
+++ b/components/resources/security_interstitials_resources.grdp
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!-- Resources for user-facing security interstitial pages. -->
 <grit-part>
   <include name="IDR_SECURITY_INTERSTITIAL_COMMON_CSS" file="../security_interstitials/core/common/resources/interstitial_common.css" compress="gzip" type="BINDATA" />
   <include name="IDR_SECURITY_INTERSTITIAL_CORE_CSS" file="../security_interstitials/core/common/resources/interstitial_core.css" compress="gzip" type="BINDATA" />
-  <include name="IDR_SECURITY_INTERSTITIAL_UI_HTML" file="../security_interstitials/core/browser/resources/list_of_interstitials.html" compress="gzip" flattenhtml="true" type="BINDATA" />
   <include name="IDR_SECURITY_INTERSTITIAL_HTML" file="../security_interstitials/core/browser/resources/interstitial_large.html" compress="gzip" flattenhtml="true" type="BINDATA"/>
   <include name="IDR_SECURITY_INTERSTITIAL_QUIET_HTML" file="../security_interstitials/core/browser/resources/interstitial_webview_quiet.html" compress="gzip" flattenhtml="true" type="BINDATA" />
   <include name="IDR_SECURITY_INTERSTITIAL_CONNECTION_HELP_HTML" file="../security_interstitials/content/resources/connection_help.html" compress="gzip" type="BINDATA" />
diff --git a/components/subresource_filter/tools/filter_many.sh b/components/subresource_filter/tools/filter_many.sh
index 6284429a4..01c349c 100755
--- a/components/subresource_filter/tools/filter_many.sh
+++ b/components/subresource_filter/tools/filter_many.sh
@@ -15,7 +15,8 @@
 #   easylist_indexed > sorted_list
 
 # The number of processes you want to run in parallel. 8 is reasonable for a
-# typical machine. 80 is good for a powerful workstation.
+# typical machine. 80 is good for a powerful workstation. If 0 is specified,
+# this script uses as many as possible.
 PROCESS_COUNT=$1
 
 # The path to the directory that contains gzip files of resource requests from
@@ -28,13 +29,22 @@
 # The path to the indexed easylist file.
 EASYLIST=$4
 
+# Create temporary directory.
+TEMP_DIR=$(mktemp -d)
+
 # For each gzip file:
 ls $GZIP_PATH/*.gz |
 
-# Unzip the file and count the number of times each rule matches.
-# Do this in parallel.
+# In parallel, unzip the file and count the number of times each rule matches.
+# The results are saved to independent temporary files to ensure that writes
+# aren't interleaved mid-rule.
 xargs -t -I {} -P $PROCESS_COUNT \
-   sh -c "gunzip -c '{}' | $FILTER_TOOL --ruleset=$EASYLIST match_rules" |
+  sh -c "gunzip -c {} | \
+         $FILTER_TOOL --ruleset=$EASYLIST match_rules \
+         > \$(mktemp $TEMP_DIR/output.XXXXXXXXXX)"
+
+# Aggregate the results from those files.
+cat $TEMP_DIR/output.* |
 
 # Sort the results by filter rule.
 sort -k 2 |
@@ -45,3 +55,6 @@
 
 # Sort the output in descending order by match count.
 sort -n -r
+
+# Delete the temporary folder.
+rm -rf $TEMP_DIR
diff --git a/components/vector_icons/BUILD.gn b/components/vector_icons/BUILD.gn
index 204b1b2..44385f8 100644
--- a/components/vector_icons/BUILD.gn
+++ b/components/vector_icons/BUILD.gn
@@ -28,6 +28,7 @@
     "folder_touch.icon",
     "forward_arrow.icon",
     "headset.icon",
+    "help.icon",
     "help_outline.icon",
     "info_outline.icon",
     "insert_drive_file_outline.icon",
diff --git a/components/vector_icons/help.icon b/components/vector_icons/help.icon
new file mode 100644
index 0000000..d4dc4c7
--- /dev/null
+++ b/components/vector_icons/help.icon
@@ -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.
+
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 12, 2,
+CUBIC_TO, 6.48f, 2, 2, 6.48f, 2, 12,
+R_CUBIC_TO, 0, 5.52f, 4.48f, 10, 10, 10,
+R_CUBIC_TO, 5.52f, 0, 10, -4.48f, 10, -10,
+CUBIC_TO_SHORTHAND, 17.52f, 2, 12, 2,
+CLOSE,
+R_MOVE_TO, 1, 17,
+R_H_LINE_TO, -2,
+R_V_LINE_TO, -2,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, 2,
+CLOSE,
+R_MOVE_TO, 2.07f, -7.75f,
+R_LINE_TO, -0.9f, 0.92f,
+CUBIC_TO, 13.45f, 12.9f, 13, 13.5f, 13, 15,
+R_H_LINE_TO, -2,
+R_V_LINE_TO, -0.5f,
+R_CUBIC_TO, 0, -1.1f, 0.45f, -2.1f, 1.17f, -2.83f,
+R_LINE_TO, 1.24f, -1.26f,
+R_CUBIC_TO, 0.37f, -0.36f, 0.59f, -0.86f, 0.59f, -1.41f,
+R_CUBIC_TO, 0, -1.1f, -0.9f, -2, -2, -2,
+R_CUBIC_TO, -1.1f, 0, -2, 0.9f, -2, 2,
+H_LINE_TO, 8,
+R_CUBIC_TO, 0, -2.21f, 1.79f, -4, 4, -4,
+R_CUBIC_TO, 2.21f, 0, 4, 1.79f, 4, 4,
+R_CUBIC_TO, 0, 0.88f, -0.36f, 1.68f, -0.93f, 2.25f,
+CLOSE
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc
index 11727ec0..9aebb2f1 100644
--- a/components/viz/common/features.cc
+++ b/components/viz/common/features.cc
@@ -16,12 +16,6 @@
 
 namespace features {
 
-// Enables running the display compositor as part of the viz service in the GPU
-// process. This is also referred to as out-of-process display compositor
-// (OOP-D).
-const base::Feature kVizDisplayCompositor{"VizDisplayCompositor",
-                                          base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Use Skia's readback API instead of GLRendererCopier.
 const base::Feature kUseSkiaForGLReadback{"UseSkiaForGLReadback",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
@@ -49,16 +43,8 @@
                                    base::FEATURE_DISABLED_BY_DEFAULT};
 
 bool IsVizDisplayCompositorEnabled() {
-  // VizDisplayCompositor is always enabled except for WebView. Since we can't
-  // differentiate between Android browser and WebView at compile time we still
-  // need to check the feature there.
-  // TODO(kylechar): Switch over any remaining places this is needed in WebView
-  // to check VizForWebView feature instead of VizDisplayCompositor.
-#if defined(OS_ANDROID)
-  return base::FeatureList::IsEnabled(kVizDisplayCompositor);
-#else
+  // TODO(crbug.com/936425): Delete function when it's no longer checked.
   return true;
-#endif
 }
 
 const base::Feature kUsePreferredIntervalForVideo{
@@ -92,12 +78,7 @@
 }
 
 bool IsUsingVizForWebView() {
-  if (base::FeatureList::IsEnabled(kVizForWebView)) {
-    DCHECK(IsVizDisplayCompositorEnabled())
-        << "Enabling VizForWebView requires VizDisplayCompositor";
-    return true;
-  }
-  return false;
+  return base::FeatureList::IsEnabled(kVizForWebView);
 }
 
 bool IsUsingPreferredIntervalForVideo() {
diff --git a/components/viz/common/features.h b/components/viz/common/features.h
index 85c05ee1..de997d1 100644
--- a/components/viz/common/features.h
+++ b/components/viz/common/features.h
@@ -14,7 +14,6 @@
 VIZ_COMMON_EXPORT extern const base::Feature kUseSkiaForGLReadback;
 VIZ_COMMON_EXPORT extern const base::Feature kUseSkiaRenderer;
 VIZ_COMMON_EXPORT extern const base::Feature kRecordSkPicture;
-VIZ_COMMON_EXPORT extern const base::Feature kVizDisplayCompositor;
 VIZ_COMMON_EXPORT extern const base::Feature kDisableDeJelly;
 VIZ_COMMON_EXPORT extern const base::Feature kVizForWebView;
 VIZ_COMMON_EXPORT extern const base::Feature kUsePreferredIntervalForVideo;
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index d4800b0..e32c85c 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -428,6 +428,10 @@
   return damage_tracker_->root_frame_missing();
 }
 
+bool Display::HasPendingSurfaces(const BeginFrameArgs& args) const {
+  return damage_tracker_->HasPendingSurfaces(args);
+}
+
 void Display::OnContextLost() {
   if (scheduler_)
     scheduler_->OutputSurfaceLost();
diff --git a/components/viz/service/display/display.h b/components/viz/service/display/display.h
index 2fb5b1d..86f67a9 100644
--- a/components/viz/service/display/display.h
+++ b/components/viz/service/display/display.h
@@ -171,6 +171,7 @@
   base::ScopedClosureRunner GetCacheBackBufferCb();
 
   bool IsRootFrameMissing() const;
+  bool HasPendingSurfaces(const BeginFrameArgs& args) const;
 
  private:
   // PresentationGroupTiming stores rendering pipeline stage timings associated
diff --git a/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc b/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc
index 198f289..911e1f0 100644
--- a/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc
+++ b/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc
@@ -74,10 +74,15 @@
     return;
   if (!pending_frame_callback_)
     return;
-  // If root frame is missing, the display scheduler will not produce a
-  // frame, so fire the pending frame callback early.
-  if (!display_->IsRootFrameMissing())
+  // If there aren't pending surfaces and the root frame is not missing,
+  // the display scheduler is likely to produce proper frame, so let it do
+  // its work. Otherwise, fire the pending frame callback early.
+  if (!display_->IsRootFrameMissing() &&
+      !display_->HasPendingSurfaces(last_begin_frame_args_)) {
     return;
+  }
+
+  frame_sink_manager_->DiscardPendingCopyOfOutputRequests(this);
 
   // All frame sinks are done with frame, yet the root frame is still missing,
   // the display won't draw, so resolve callback now.
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
index 8cae303..7cee616 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -626,6 +626,22 @@
   return it->second.preferred_frame_interval;
 }
 
+void FrameSinkManagerImpl::DiscardPendingCopyOfOutputRequests(
+    const BeginFrameSource* source) {
+  const auto& root_sink = registered_sources_.at(source);
+  base::queue<FrameSinkId> queue;
+  for (queue.push(root_sink); !queue.empty(); queue.pop()) {
+    auto& frame_sink_id = queue.front();
+    auto support = support_map_.find(frame_sink_id);
+    // The returned copy requests are destroyed upon going out of scope, which
+    // invokes the pending callbacks.
+    if (support != support_map_.end())
+      support->second->TakeCopyOutputRequests(LocalSurfaceId::MaxSequenceId());
+    for (auto child : GetChildrenByParent(frame_sink_id))
+      queue.push(child);
+  }
+}
+
 void FrameSinkManagerImpl::CacheBackBuffer(
     uint32_t cache_id,
     const FrameSinkId& root_frame_sink_id) {
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.h b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
index cacc1e0..fb4ec523 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.h
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
@@ -225,6 +225,13 @@
   base::TimeDelta GetPreferredFrameIntervalForFrameSinkId(
       const FrameSinkId& id) const;
 
+  // This cancels pending output requests owned by the frame sinks associated
+  // with the specified BeginFrameSource.
+  // The requets callback will be fired as part of request destruction.
+  // This may be used in case we know a frame can't be produced any time soon,
+  // so there's no point for caller to wait for the copy of output.
+  void DiscardPendingCopyOfOutputRequests(const BeginFrameSource* source);
+
  private:
   friend class FrameSinkManagerTest;
 
diff --git a/content/browser/appcache/appcache_cache_test_helper.cc b/content/browser/appcache/appcache_cache_test_helper.cc
new file mode 100644
index 0000000..9a2fec4
--- /dev/null
+++ b/content/browser/appcache/appcache_cache_test_helper.cc
@@ -0,0 +1,231 @@
+// 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/appcache/appcache_cache_test_helper.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "content/browser/appcache/appcache_response.h"
+#include "net/http/http_response_headers.h"
+
+namespace content {
+
+namespace {
+const int kAppCacheFetchBufferSize = 32768;
+}  // namespace
+
+AppCacheCacheTestHelper::CacheEntry::CacheEntry(
+    int types,
+    std::string expect_if_modified_since,
+    std::string expect_if_none_match,
+    bool headers_allowed,
+    std::unique_ptr<net::HttpResponseInfo> response_info,
+    const std::string& body)
+    : types(types),
+      expect_if_modified_since(expect_if_modified_since),
+      expect_if_none_match(expect_if_none_match),
+      headers_allowed(headers_allowed),
+      response_info(std::move(response_info)),
+      body(body) {}
+
+AppCacheCacheTestHelper::CacheEntry::~CacheEntry() = default;
+
+// static
+void AppCacheCacheTestHelper::AddCacheEntry(
+    CacheEntries* cache_entries,
+    const GURL& url,
+    int types,
+    std::string expect_if_modified_since,
+    std::string expect_if_none_match,
+    bool headers_allowed,
+    std::unique_ptr<net::HttpResponseInfo> response_info,
+    const std::string& body) {
+  cache_entries->emplace(
+      url, std::make_unique<AppCacheCacheTestHelper::CacheEntry>(
+               types, expect_if_modified_since, expect_if_none_match,
+               headers_allowed, std::move(response_info), body));
+}
+
+AppCacheCacheTestHelper::AppCacheCacheTestHelper(
+    const MockAppCacheService* service,
+    const GURL& manifest_url,
+    AppCache* const cache,
+    CacheEntries cache_entries,
+    base::OnceCallback<void(int)> post_write_callback)
+    : service_(service),
+      manifest_url_(manifest_url),
+      cache_(cache),
+      cache_entries_(std::move(cache_entries)),
+      post_write_callback_(std::move(post_write_callback)) {}
+
+AppCacheCacheTestHelper::~AppCacheCacheTestHelper() = default;
+
+void AppCacheCacheTestHelper::PrepareForRead(
+    AppCache* read_cache,
+    base::OnceClosure post_read_callback) {
+  read_cache_ = read_cache;
+  post_read_callback_ = std::move(post_read_callback);
+}
+
+void AppCacheCacheTestHelper::Read() {
+  state_ = State::kReadInfo;
+  read_it_ = read_cache_->entries().begin();
+  read_cache_entries_.clear();
+  AsyncRead(0);
+}
+
+void AppCacheCacheTestHelper::Write() {
+  state_ = State::kWriteInfo;
+  write_it_ = cache_entries_.begin();
+  AsyncWrite(0);
+}
+
+void AppCacheCacheTestHelper::OnResponseInfoLoaded(
+    AppCacheResponseInfo* response_info,
+    int64_t response_id) {
+  DCHECK(response_info);
+  DCHECK_EQ(read_entry_response_id_, response_id);
+
+  read_info_response_info_.reset();
+  read_info_response_info_ = response_info;
+  AsyncRead(0);
+}
+
+void AppCacheCacheTestHelper::AsyncRead(int result) {
+  DCHECK(state_ == State::kReadInfo || state_ == State::kReadData);
+  DCHECK_GE(result, 0);
+  if (read_it_ == read_cache_->entries().end()) {
+    std::move(post_read_callback_).Run();
+    return;
+  }
+  switch (state_) {
+    case State::kReadInfo: {
+      if (!read_info_response_info_) {
+        AppCacheEntry* entry = read_cache_->GetEntry(read_it_->first);
+        DCHECK(entry);
+        read_entry_response_id_ = entry->response_id();
+        service_->storage()->LoadResponseInfo(manifest_url_,
+                                              read_entry_response_id_, this);
+      } else {
+        // Result is in |read_info_response_info_|.  Keep it there for now.
+        // Will be passed along after data is read.
+
+        // Prepare for next state.
+        state_ = State::kReadData;
+
+        // Trigger data read for |read_entry_response_id_|.
+        read_data_response_reader_ = service_->storage()->CreateResponseReader(
+            read_it_->first, read_entry_response_id_);
+        read_data_buffer_ =
+            base::MakeRefCounted<net::IOBuffer>(kAppCacheFetchBufferSize);
+        read_data_response_reader_->ReadData(
+            read_data_buffer_.get(), kAppCacheFetchBufferSize,
+            base::BindOnce(&AppCacheCacheTestHelper::AsyncRead,
+                           base::Unretained(this)));
+      }
+    } break;
+    case State::kReadData: {
+      if (result > 0) {
+        read_data_loaded_data_.append(read_data_buffer_->data(), result);
+        read_data_response_reader_->ReadData(
+            read_data_buffer_.get(), kAppCacheFetchBufferSize,
+            base::BindOnce(&AppCacheCacheTestHelper::AsyncRead,
+                           base::Unretained(this)));
+      } else {
+        // Result is in |read_data_loaded_data_|.
+
+        std::unique_ptr<net::HttpResponseInfo> http_response_info =
+            std::make_unique<net::HttpResponseInfo>(
+                read_info_response_info_->http_response_info());
+        AppCacheCacheTestHelper::AddCacheEntry(
+            &read_cache_entries_, read_it_->first, AppCacheEntry::EXPLICIT,
+            /*expect_if_modified_since=*/std::string(),
+            /*expect_if_none_match=*/std::string(), /*headers_allowed=*/false,
+            std::move(http_response_info), read_data_loaded_data_);
+
+        // Reset after read.
+        read_info_response_info_.reset();
+        read_entry_response_id_ = 0;
+        read_data_buffer_ = nullptr;
+        read_data_loaded_data_ = "";
+        read_data_response_reader_.reset();
+
+        // Prepare for next state.
+        state_ = State::kReadInfo;
+        read_it_++;  // move to next entry
+        base::ThreadTaskRunnerHandle::Get()->PostTask(
+            FROM_HERE, base::BindOnce(&AppCacheCacheTestHelper::AsyncRead,
+                                      base::Unretained(this), 0));
+      }
+    } break;
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
+void AppCacheCacheTestHelper::AsyncWrite(int result) {
+  DCHECK(state_ == State::kWriteInfo || state_ == State::kWriteData);
+  DCHECK_GE(result, 0);
+  if (write_it_ == cache_entries_.end()) {
+    std::move(post_write_callback_).Run(1);
+    return;
+  }
+  switch (state_) {
+    case State::kWriteInfo: {
+      // Prepare for info write.
+      response_writer_.reset();
+      response_writer_ =
+          service_->storage()->CreateResponseWriter(manifest_url_);
+      AppCacheEntry* entry = cache_->GetEntry(write_it_->first);
+      if (entry) {
+        entry->add_types(write_it_->second->types);
+        entry->set_response_id(response_writer_->response_id());
+      } else {
+        cache_->AddEntry(write_it_->first,
+                         AppCacheEntry(write_it_->second->types,
+                                       response_writer_->response_id()));
+      }
+      // Copy |response_info| so later calls can access the original response
+      // info.
+      std::unique_ptr<net::HttpResponseInfo> http_response_info =
+          std::make_unique<net::HttpResponseInfo>(
+              *(write_it_->second->response_info));
+      scoped_refptr<HttpResponseInfoIOBuffer> io_buffer =
+          base::MakeRefCounted<HttpResponseInfoIOBuffer>(
+              std::move(http_response_info));
+
+      // Prepare for next state.
+      state_ = State::kWriteData;
+
+      // Trigger async WriteInfo() call.
+      response_writer_->WriteInfo(
+          io_buffer.get(), base::BindOnce(&AppCacheCacheTestHelper::AsyncWrite,
+                                          base::Unretained(this)));
+    } break;
+    case State::kWriteData: {
+      // Prepare for data write.
+      std::string body = write_it_->second->body;
+      scoped_refptr<net::StringIOBuffer> io_buffer =
+          base::MakeRefCounted<net::StringIOBuffer>(body);
+
+      // Prepare for next state.
+      state_ = State::kWriteInfo;
+      write_it_++;  // move to next entry
+
+      // Trigger async WriteData() call.
+      response_writer_->WriteData(
+          io_buffer.get(), body.length(),
+          base::BindOnce(&AppCacheCacheTestHelper::AsyncWrite,
+                         base::Unretained(this)));
+    } break;
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
+}  // namespace content
diff --git a/content/browser/appcache/appcache_cache_test_helper.h b/content/browser/appcache/appcache_cache_test_helper.h
new file mode 100644
index 0000000..65355aad
--- /dev/null
+++ b/content/browser/appcache/appcache_cache_test_helper.h
@@ -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.
+
+#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_CACHE_TEST_HELPER_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_CACHE_TEST_HELPER_H_
+
+#include "content/browser/appcache/mock_appcache_service.h"
+
+namespace content {
+
+// Helper class to read cache info from and write cache info to disk.
+class AppCacheCacheTestHelper : public AppCacheStorage::Delegate {
+ public:
+  // Helpers to collect cache entry information in a single location.
+  struct CacheEntry {
+    CacheEntry(int types,
+               std::string expect_if_modified_since,
+               std::string expect_if_none_match,
+               bool headers_allowed,
+               std::unique_ptr<net::HttpResponseInfo> response_info,
+               const std::string& body);
+    ~CacheEntry();
+
+    int types;  // The combination of AppCacheEntry::Type values for this entry.
+    std::string expect_if_modified_since;
+    std::string expect_if_none_match;
+    bool headers_allowed = true;
+    std::unique_ptr<net::HttpResponseInfo> response_info;
+    std::string body;
+  };
+
+  using CacheEntries = std::map<GURL, std::unique_ptr<CacheEntry>>;
+
+  static void AddCacheEntry(
+      CacheEntries* cache_entries,
+      const GURL& url,
+      int types,
+      std::string expect_if_modified_since,
+      std::string expect_if_none_match,
+      bool headers_allowed,
+      std::unique_ptr<net::HttpResponseInfo> response_info,
+      const std::string& body);
+
+  AppCacheCacheTestHelper(const MockAppCacheService* service,
+                          const GURL& manifest_url,
+                          AppCache* const cache,
+                          CacheEntries cache_entries,
+                          base::OnceCallback<void(int)> post_write_callback);
+  ~AppCacheCacheTestHelper() override;
+
+  AppCache* write_cache() { return cache_; }
+  const CacheEntries& cache_entries() { return cache_entries_; }
+  const CacheEntries& read_cache_entries() { return read_cache_entries_; }
+
+  void PrepareForRead(AppCache* cache, base::OnceClosure post_read_callback);
+  void Read();
+  void Write();
+  void OnResponseInfoLoaded(AppCacheResponseInfo* response_info,
+                            int64_t response_id) override;
+
+ private:
+  enum class State {
+    kReadInfo,
+    kReadData,
+    kWriteInfo,
+    kWriteData,
+  };
+
+  void AsyncRead(int result);
+  void AsyncWrite(int result);
+
+  const MockAppCacheService* const service_;
+  const GURL manifest_url_;
+  AppCache* const cache_;
+  CacheEntries cache_entries_;
+  base::OnceCallback<void(int)> post_write_callback_;
+  State state_;
+
+  // Used for writing cache info and data.
+  CacheEntries::const_iterator write_it_;
+  std::unique_ptr<AppCacheResponseWriter> response_writer_;
+
+  // Used for reading cache info and data.
+  AppCache* read_cache_;
+  AppCache::EntryMap::const_iterator read_it_;
+  int64_t read_entry_response_id_;
+  scoped_refptr<AppCacheResponseInfo> read_info_response_info_;
+  scoped_refptr<net::IOBuffer> read_data_buffer_;
+  std::string read_data_loaded_data_;
+  std::unique_ptr<AppCacheResponseReader> read_data_response_reader_;
+  CacheEntries read_cache_entries_;
+  base::OnceClosure post_read_callback_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_APPCACHE_APPCACHE_CACHE_TEST_HELPER_H_
diff --git a/content/browser/appcache/appcache_cache_test_helper_unittest.cc b/content/browser/appcache/appcache_cache_test_helper_unittest.cc
new file mode 100644
index 0000000..b1f7a48
--- /dev/null
+++ b/content/browser/appcache/appcache_cache_test_helper_unittest.cc
@@ -0,0 +1,419 @@
+// 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/appcache/appcache_cache_test_helper.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/task/post_task.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_host.h"
+#include "content/browser/appcache/appcache_response.h"
+#include "content/browser/appcache/appcache_update_job.h"
+#include "content/browser/appcache/mock_appcache_service.h"
+#include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/storage_partition_impl.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/test_browser_context.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
+#include "third_party/blink/public/mojom/appcache/appcache_info.mojom.h"
+
+namespace content {
+namespace appcache_cache_test_helper_unittest {
+
+class AppCacheCacheTestHelperTest;
+
+// Values should match values used in appcache_update_job.cc.
+const base::TimeDelta kOneHour = base::TimeDelta::FromHours(1);
+
+const char kManifest1Contents[] =
+    "CACHE MANIFEST\n"
+    "explicit1\n"
+    "FALLBACK:\n"
+    "fallback1 fallback1a\n"
+    "NETWORK:\n"
+    "*\n";
+
+// There are a handful of http accessible resources that we need to conduct
+// these tests. Instead of running a separate server to host these resources,
+// we mock them up.
+class MockHttpServer {
+ public:
+  static GURL GetMockUrl(const std::string& path) {
+    return GURL("http://mockhost/" + path);
+  }
+
+  static void GetMockResponse(const std::string& path,
+                              std::string* headers,
+                              std::string* body) {
+    const char not_found_headers[] =
+        "HTTP/1.1 404 NOT FOUND\n"
+        "\n";
+    (*headers) = std::string(not_found_headers, base::size(not_found_headers));
+    (*body) = "";
+  }
+};
+
+inline bool operator==(const AppCacheNamespace& lhs,
+                       const AppCacheNamespace& rhs) {
+  return lhs.type == rhs.type && lhs.namespace_url == rhs.namespace_url &&
+         lhs.target_url == rhs.target_url;
+}
+
+class MockFrontend : public blink::mojom::AppCacheFrontend {
+ public:
+  MockFrontend()
+      : ignore_progress_events_(false),
+        verify_progress_events_(false),
+        last_progress_total_(-1),
+        last_progress_complete_(-1),
+        start_update_trigger_(
+            blink::mojom::AppCacheEventID::APPCACHE_CHECKING_EVENT),
+        update_(nullptr) {}
+
+  void CacheSelected(blink::mojom::AppCacheInfoPtr info) override {}
+
+  void EventRaised(blink::mojom::AppCacheEventID event_id) override {
+    raised_events_.push_back(event_id);
+
+    // Trigger additional updates if requested.
+    if (event_id == start_update_trigger_ && update_) {
+      for (AppCacheHost* host : update_hosts_) {
+        update_->StartUpdate(
+            host, (host ? host->pending_master_entry_url() : GURL()));
+      }
+      update_hosts_.clear();  // only trigger once
+    }
+  }
+
+  void ErrorEventRaised(
+      blink::mojom::AppCacheErrorDetailsPtr details) override {
+    error_message_ = details->message;
+    EventRaised(blink::mojom::AppCacheEventID::APPCACHE_ERROR_EVENT);
+  }
+
+  void ProgressEventRaised(const GURL& url,
+                           int32_t num_total,
+                           int32_t num_complete) override {
+    if (!ignore_progress_events_)
+      EventRaised(blink::mojom::AppCacheEventID::APPCACHE_PROGRESS_EVENT);
+
+    if (verify_progress_events_) {
+      EXPECT_GE(num_total, num_complete);
+      EXPECT_GE(num_complete, 0);
+
+      if (last_progress_total_ == -1) {
+        // Should start at zero.
+        EXPECT_EQ(0, num_complete);
+      } else {
+        // Total should be stable and complete should bump up by one at a time.
+        EXPECT_EQ(last_progress_total_, num_total);
+        EXPECT_EQ(last_progress_complete_ + 1, num_complete);
+      }
+
+      // Url should be valid for all except the 'final' event.
+      if (num_total == num_complete)
+        EXPECT_TRUE(url.is_empty());
+      else
+        EXPECT_TRUE(url.is_valid());
+
+      last_progress_total_ = num_total;
+      last_progress_complete_ = num_complete;
+    }
+  }
+
+  void LogMessage(blink::mojom::ConsoleMessageLevel log_level,
+                  const std::string& message) override {}
+
+  void SetSubresourceFactory(
+      mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory)
+      override {}
+
+  void AddExpectedEvent(blink::mojom::AppCacheEventID event_id) {
+    DCHECK(!ignore_progress_events_ ||
+           event_id != blink::mojom::AppCacheEventID::APPCACHE_PROGRESS_EVENT);
+    expected_events_.push_back(event_id);
+  }
+
+  void SetIgnoreProgressEvents(bool ignore) {
+    // Some tests involve joining new hosts to an already running update job
+    // or intentionally failing. The timing and sequencing of the progress
+    // events generated by an update job are dependent on the behavior of
+    // an external HTTP server. For jobs that do not run fully till completion,
+    // due to either joining late or early exit, we skip monitoring the
+    // progress events to avoid flakiness.
+    ignore_progress_events_ = ignore;
+  }
+
+  void SetVerifyProgressEvents(bool verify) {
+    verify_progress_events_ = verify;
+  }
+
+  void TriggerAdditionalUpdates(blink::mojom::AppCacheEventID trigger_event,
+                                AppCacheUpdateJob* update) {
+    start_update_trigger_ = trigger_event;
+    update_ = update;
+  }
+
+  void AdditionalUpdateHost(AppCacheHost* host) {
+    update_hosts_.push_back(host);
+  }
+
+  using RaisedEvents = std::vector<blink::mojom::AppCacheEventID>;
+  RaisedEvents raised_events_;
+  std::string error_message_;
+
+  // Set the expected events if verification needs to happen asynchronously.
+  RaisedEvents expected_events_;
+  std::string expected_error_message_;
+
+  bool ignore_progress_events_;
+
+  bool verify_progress_events_;
+  int last_progress_total_;
+  int last_progress_complete_;
+
+  // Add ability for frontend to add master entries to an inprogress update.
+  blink::mojom::AppCacheEventID start_update_trigger_;
+  AppCacheUpdateJob* update_;
+  std::vector<AppCacheHost*> update_hosts_;
+};
+
+class AppCacheCacheTestHelperTest : public testing::Test {
+ public:
+  AppCacheCacheTestHelperTest()
+      : process_id_(123),
+        weak_partition_factory_(static_cast<StoragePartitionImpl*>(
+            BrowserContext::GetDefaultStoragePartition(&browser_context_))) {}
+
+  void SetUp() override {
+    ChildProcessSecurityPolicyImpl::GetInstance()->Add(process_id_,
+                                                       &browser_context_);
+  }
+
+  void TearDown() override {
+    ChildProcessSecurityPolicyImpl::GetInstance()->Remove(process_id_);
+  }
+  // Use a separate IO thread to run a test. Thread will be destroyed
+  // when it goes out of scope.
+  template <class Method>
+  void RunTestOnUIThread(Method method) {
+    base::RunLoop run_loop;
+    test_completed_cb_ = run_loop.QuitClosure();
+    base::PostTask(FROM_HERE, {BrowserThread::UI},
+                   base::BindOnce(method, base::Unretained(this)));
+    run_loop.Run();
+  }
+
+  void BasicStart() {
+    MakeService();
+    group_ = base::MakeRefCounted<AppCacheGroup>(
+        service_->storage(), MockHttpServer::GetMockUrl("files/manifest1"),
+        111);
+
+    // Create a cache without a manifest entry.  The manifest entry will be
+    // added later.
+    AppCache* cache = MakeCacheForGroup(service_->storage()->NewCacheId(), -1);
+    MockFrontend* frontend = MakeMockFrontend();
+    AppCacheHost* host = MakeHost(frontend);
+    host->AssociateCompleteCache(cache);
+
+    AppCacheCacheTestHelper::CacheEntries cache_entries;
+
+    // Add cache entry for manifest.
+    const char data[] =
+        "HTTP/1.1 200 OK\0"
+        "Last-Modified: Sat, 29 Oct 1994 19:43:31 GMT\0";
+    scoped_refptr<net::HttpResponseHeaders> headers =
+        base::MakeRefCounted<net::HttpResponseHeaders>(
+            std::string(data, base::size(data)));
+    std::unique_ptr<net::HttpResponseInfo> response_info =
+        std::make_unique<net::HttpResponseInfo>();
+    response_info->headers = std::move(headers);
+    AppCacheCacheTestHelper::AddCacheEntry(
+        &cache_entries, group_->manifest_url(), AppCacheEntry::EXPLICIT,
+        /*expect_if_modified_since=*/"Sat, 29 Oct 1994 19:43:31 GMT",
+        /*expect_if_none_match=*/std::string(), /*headers_allowed=*/true,
+        std::move(response_info), kManifest1Contents);
+
+    cache_helper_ = std::make_unique<AppCacheCacheTestHelper>(
+        service_.get(), group_->manifest_url(), cache, std::move(cache_entries),
+        base::BindOnce(&AppCacheCacheTestHelperTest::BasicWriteFinished,
+                       base::Unretained(this)));
+    cache_helper_->Write();
+    // Continues async in |BasicWriteFinished|.
+  }
+
+  void BasicWriteFinished(int result) {
+    cache_helper_->PrepareForRead(
+        group_->newest_complete_cache(),
+        base::BindOnce(&AppCacheCacheTestHelperTest::BasicReadFinished,
+                       base::Unretained(this)));
+    cache_helper_->Read();
+    // Continues async in |BasicReadFinished|.
+  }
+
+  void BasicReadFinished() {
+    EXPECT_EQ(cache_helper_->cache_entries().size(),
+              cache_helper_->read_cache_entries().size());
+    for (auto it = cache_helper_->cache_entries().begin();
+         it != cache_helper_->cache_entries().end(); ++it) {
+      auto read_it = cache_helper_->read_cache_entries().find(it->first);
+
+      EXPECT_EQ(it->second->response_info->headers->raw_headers(),
+                read_it->second->response_info->headers->raw_headers());
+
+      EXPECT_EQ(it->second->body, read_it->second->body);
+    }
+
+    Finished();
+  }
+
+  void Finished() {
+    // We unwind the stack prior to finishing up to let stack-based objects
+    // get deleted.
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(&AppCacheCacheTestHelperTest::FinishedUnwound,
+                                  base::Unretained(this)));
+  }
+
+  void FinishedUnwound() {
+    // Clean up everything that was created on the IO thread.
+    cache_helper_.reset();
+    protect_newest_cache_ = nullptr;
+    group_ = nullptr;
+    hosts_.clear();
+    frontends_.clear();
+    response_infos_.clear();
+    service_.reset(nullptr);
+
+    std::move(test_completed_cb_).Run();
+  }
+
+  void MakeService() {
+    service_ = std::make_unique<MockAppCacheService>(
+        weak_partition_factory_.GetWeakPtr());
+  }
+
+  AppCache* MakeCacheForGroup(int64_t cache_id, int64_t manifest_response_id) {
+    return MakeCacheForGroup(cache_id, group_->manifest_url(),
+                             manifest_response_id);
+  }
+
+  AppCache* MakeCacheForGroup(int64_t cache_id,
+                              const GURL& manifest_entry_url,
+                              int64_t manifest_response_id) {
+    AppCache* cache = new AppCache(service_->storage(), cache_id);
+    cache->set_complete(true);
+    cache->set_manifest_parser_version(1);
+    cache->set_manifest_scope("/");
+    cache->set_update_time(base::Time::Now() - kOneHour);
+    group_->AddCache(cache);
+    group_->set_last_full_update_check_time(cache->update_time());
+
+    // Add manifest entry to cache.
+    if (manifest_response_id >= 0) {
+      cache->AddEntry(manifest_entry_url, AppCacheEntry(AppCacheEntry::MANIFEST,
+                                                        manifest_response_id));
+    }
+
+    // Specific tests that expect a newer time should set
+    // expect_full_update_time_newer_than_ which causes this
+    // equality expectation to be ignored.
+    expect_full_update_time_equal_to_ = cache->update_time();
+
+    return cache;
+  }
+
+  AppCacheHost* MakeHost(blink::mojom::AppCacheFrontend* frontend) {
+    constexpr int kRenderFrameIdForTests = 456;
+    hosts_.push_back(std::make_unique<AppCacheHost>(
+        base::UnguessableToken::Create(), process_id_, kRenderFrameIdForTests,
+        mojo::NullRemote(), service_.get()));
+    hosts_.back()->set_frontend_for_testing(frontend);
+    return hosts_.back().get();
+  }
+
+  AppCacheResponseInfo* MakeAppCacheResponseInfo(
+      const GURL& manifest_url,
+      int64_t response_id,
+      const std::string& raw_headers) {
+    std::unique_ptr<net::HttpResponseInfo> http_info =
+        std::make_unique<net::HttpResponseInfo>();
+    http_info->headers =
+        base::MakeRefCounted<net::HttpResponseHeaders>(raw_headers);
+    auto info = base::MakeRefCounted<AppCacheResponseInfo>(
+        service_->storage()->GetWeakPtr(), manifest_url, response_id,
+        std::move(http_info), 0);
+    response_infos_.emplace_back(info);
+    return info.get();
+  }
+
+  MockFrontend* MakeMockFrontend() {
+    frontends_.push_back(std::make_unique<MockFrontend>());
+    return frontends_.back().get();
+  }
+
+ private:
+  content::BrowserTaskEnvironment task_environment_;
+
+  std::unique_ptr<MockAppCacheService> service_;
+  scoped_refptr<AppCacheGroup> group_;
+  scoped_refptr<AppCache> protect_newest_cache_;
+  base::OnceClosure test_completed_cb_;
+
+  std::unique_ptr<AppCacheResponseWriter> response_writer_;
+  std::unique_ptr<AppCacheCacheTestHelper> cache_helper_;
+
+  // Hosts used by an async test that need to live until update job finishes.
+  // Otherwise, test can put host on the stack instead of here.
+  std::vector<std::unique_ptr<AppCacheHost>> hosts_;
+
+  // Response infos used by an async test that need to live until update job
+  // finishes.
+  std::vector<scoped_refptr<AppCacheResponseInfo>> response_infos_;
+
+  // Flag indicating if test cares to verify the update after update finishes.
+  base::Time expect_full_update_time_equal_to_;
+  std::vector<std::unique_ptr<MockFrontend>>
+      frontends_;  // to check expected events
+  AppCache::EntryMap expect_extra_entries_;
+  std::map<GURL, int64_t> expect_response_ids_;
+
+  content::TestBrowserContext browser_context_;
+  const int process_id_;
+  base::WeakPtrFactory<StoragePartitionImpl> weak_partition_factory_;
+};
+
+TEST_F(AppCacheCacheTestHelperTest, Basic) {
+  RunTestOnUIThread(&AppCacheCacheTestHelperTest::BasicStart);
+}
+
+}  // namespace appcache_cache_test_helper_unittest
+}  // namespace content
diff --git a/content/browser/appcache/appcache_group.h b/content/browser/appcache/appcache_group.h
index 63c1bb5..848c5376 100644
--- a/content/browser/appcache/appcache_group.h
+++ b/content/browser/appcache/appcache_group.h
@@ -29,6 +29,12 @@
 FORWARD_DECLARE_TEST(AppCacheUpdateJobTest, AlreadyDownloading);
 }  // namespace appcache_update_job_unittest
 
+namespace appcache_cache_helper_unittest {
+class AppCacheCacheHelperTest;
+FORWARD_DECLARE_TEST(AppCacheCacheHelperTest,
+                     IfModifiedSinceUpgradeParserVersion0);
+}  // namespace appcache_cache_helper_unittest
+
 FORWARD_DECLARE_TEST(AppCacheGroupTest, StartUpdate);
 FORWARD_DECLARE_TEST(AppCacheGroupTest, CancelUpdate);
 FORWARD_DECLARE_TEST(AppCacheGroupTest, QueueUpdate);
@@ -206,6 +212,9 @@
   FRIEND_TEST_ALL_PREFIXES(
       content::appcache_update_job_unittest::AppCacheUpdateJobTest,
       AlreadyDownloading);
+  FRIEND_TEST_ALL_PREFIXES(
+      content::appcache_cache_helper_unittest::AppCacheCacheHelperTest,
+      IfModifiedSinceUpgradeParserVersion0);
 
   DISALLOW_COPY_AND_ASSIGN(AppCacheGroup);
 };
diff --git a/content/browser/appcache/appcache_request_handler.cc b/content/browser/appcache/appcache_request_handler.cc
index 9c8972d..5cbd9f8 100644
--- a/content/browser/appcache/appcache_request_handler.cc
+++ b/content/browser/appcache/appcache_request_handler.cc
@@ -439,7 +439,7 @@
               frame_tree_node->navigation_request()->GetNavigationId(),
               &factory_receiver, nullptr /* header_client */,
               nullptr /* bypass_redirect_checks */,
-              nullptr /* factory_override */);
+              nullptr /* disable_secure_dns */, nullptr /* factory_override */);
       if (use_proxy) {
         single_request_factory->Clone(std::move(factory_receiver));
         single_request_factory =
diff --git a/content/browser/appcache/appcache_update_job_unittest.cc b/content/browser/appcache/appcache_update_job_unittest.cc
index acae2be..dfbe749 100644
--- a/content/browser/appcache/appcache_update_job_unittest.cc
+++ b/content/browser/appcache/appcache_update_job_unittest.cc
@@ -97,7 +97,7 @@
     "/ /fallback-newroot/foo\n";
 
 // There are a handful of http accessible resources that we need to conduct
-// these tests. Instead of running a seperate server to host these resources,
+// these tests. Instead of running a separate server to host these resources,
 // we mock them up.
 class MockHttpServer {
  public:
@@ -673,10 +673,10 @@
         expect_non_null_update_time_(false),
         tested_manifest_(NONE),
         tested_manifest_path_override_(nullptr),
-        weak_partition_factory_(static_cast<StoragePartitionImpl*>(
-            BrowserContext::GetDefaultStoragePartition(&browser_context_))),
         interceptor_(base::BindRepeating(&InterceptRequest)),
-        process_id_(123) {}
+        process_id_(123),
+        weak_partition_factory_(static_cast<StoragePartitionImpl*>(
+            BrowserContext::GetDefaultStoragePartition(&browser_context_))) {}
 
   void SetUp() override {
     ChildProcessSecurityPolicyImpl::GetInstance()->Add(process_id_,
@@ -4577,9 +4577,9 @@
   std::map<GURL, int64_t> expect_response_ids_;
 
   content::TestBrowserContext browser_context_;
-  base::WeakPtrFactory<StoragePartitionImpl> weak_partition_factory_;
   URLLoaderInterceptor interceptor_;
   const int process_id_;
+  base::WeakPtrFactory<StoragePartitionImpl> weak_partition_factory_;
 };
 
 TEST_F(AppCacheUpdateJobTest, AlreadyChecking) {
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index 5abfb1c..e319ad4 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -252,7 +252,7 @@
         ContentBrowserClient::URLLoaderFactoryType::kDownload, url::Origin(),
         base::nullopt /* navigation_id */, &maybe_proxy_factory_receiver,
         nullptr /* header_client */, nullptr /* bypass_redirect_checks */,
-        nullptr /* factory_override */);
+        nullptr /* disable_secure_dns */, nullptr /* factory_override */);
 
     // If anyone above indicated that they care about proxying, pass the
     // intermediate pipe along to the NetworkDownloadPendingURLLoaderFactory.
diff --git a/content/browser/find_request_manager.cc b/content/browser/find_request_manager.cc
index 4e91108..c7f728c 100644
--- a/content/browser/find_request_manager.cc
+++ b/content/browser/find_request_manager.cc
@@ -409,6 +409,14 @@
     find_in_page_clients_.erase(it);
   }
 
+  // If this is a main frame, then clear the search queue as well, since we
+  // shouldn't be dispatching any more requests. Note that if any other frame is
+  // removed, we can target any queued requests to the focused frame or main
+  // frame. However, if the main frame is removed we will not have a valid
+  // RenderFrameHost to target for the request queue.
+  if (!rfh->GetParent())
+    find_request_queue_ = base::queue<FindRequest>();
+
   // Update the active match ordinal, since it may have changed.
   if (active_frame_ == rfh) {
     active_frame_ = nullptr;
diff --git a/content/browser/find_request_manager_browsertest.cc b/content/browser/find_request_manager_browsertest.cc
index 7eae63a..e6f273c 100644
--- a/content/browser/find_request_manager_browsertest.cc
+++ b/content/browser/find_request_manager_browsertest.cc
@@ -390,6 +390,25 @@
   EXPECT_EQ(8, results.active_match_ordinal);
 }
 
+IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, RemoveMainFrame) {
+  LoadAndWait("/find_in_page.html");
+
+  auto options = blink::mojom::FindOptions::New();
+  options->run_synchronously_for_testing = true;
+  Find("result", options->Clone());
+  delegate()->WaitForFinalReply();
+  options->find_next = true;
+  options->forward = false;
+  Find("result", options->Clone());
+  Find("result", options->Clone());
+  Find("result", options->Clone());
+  Find("result", options->Clone());
+  Find("result", options->Clone());
+
+  // Don't wait for the reply, and end the test. This will remove the main
+  // frame, which should not crash.
+}
+
 // Tests adding a frame during a find session.
 // TODO(crbug.com/657331): Test is flaky on all platforms.
 IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, DISABLED_AddFrame) {
diff --git a/content/browser/frame_host/navigation_request_browsertest.cc b/content/browser/frame_host/navigation_request_browsertest.cc
index 1ff7285..38de5db 100644
--- a/content/browser/frame_host/navigation_request_browsertest.cc
+++ b/content/browser/frame_host/navigation_request_browsertest.cc
@@ -1643,7 +1643,7 @@
 
   EXPECT_TRUE(observer.has_committed());
   EXPECT_TRUE(observer.is_error());
-  EXPECT_EQ(net::ERR_DNS_TIMED_OUT, observer.net_error_code());
+  EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, observer.net_error_code());
   EXPECT_EQ(net::ERR_DNS_TIMED_OUT, observer.resolve_error_info().error);
 }
 
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 0177050..35af015 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -5323,7 +5323,7 @@
               main_world_origin_for_url_loader_factory,
               base::nullopt /* navigation_id */, &appcache_proxied_receiver,
               nullptr /* header_client */, nullptr /* bypass_redirect_checks */,
-              nullptr /* factory_override */);
+              nullptr /* disable_secure_dns */, nullptr /* factory_override */);
       if (use_proxy) {
         appcache_remote->Clone(std::move(appcache_proxied_receiver));
         appcache_remote.reset();
@@ -5353,7 +5353,7 @@
           main_world_origin_for_url_loader_factory,
           base::nullopt /* navigation_id */, &factory_receiver,
           nullptr /* header_client */, nullptr /* bypass_redirect_checks */,
-          nullptr /* factory_override */);
+          nullptr /* disable_secure_dns */, nullptr /* factory_override */);
       CreateWebUIURLLoaderBinding(this, scheme, std::move(factory_receiver));
       // If the renderer has webui bindings, then don't give it access to
       // network loader for security reasons.
@@ -5477,7 +5477,7 @@
           main_world_origin_for_url_loader_factory,
           base::nullopt /* navigation_id */, &factory_receiver,
           nullptr /* header_client */, nullptr /* bypass_redirect_checks */,
-          nullptr /* factory_override */);
+          nullptr /* disable_secure_dns */, nullptr /* factory_override */);
       // Keep DevTools proxy last, i.e. closest to the network.
       devtools_instrumentation::WillCreateURLLoaderFactory(
           this, false /* is_navigation */, false /* is_download */,
@@ -6174,7 +6174,7 @@
       ContentBrowserClient::URLLoaderFactoryType::kDocumentSubResource, origin,
       base::nullopt /* navigation_id */, &default_factory_receiver,
       &params->header_client, &bypass_redirect_checks,
-      &params->factory_override);
+      &params->disable_secure_dns, &params->factory_override);
 
   // Keep DevTools proxy last, i.e. closest to the network.
   devtools_instrumentation::WillCreateURLLoaderFactory(
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 8f84049..7f32217 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -1319,7 +1319,8 @@
         ContentBrowserClient::URLLoaderFactoryType::kNavigation, url::Origin(),
         frame_tree_node->navigation_request()->GetNavigationId(),
         &factory_receiver, nullptr /* header_client */,
-        nullptr /* bypass_redirect_checks */, nullptr /* factory_override */);
+        nullptr /* bypass_redirect_checks */, nullptr /* disable_secure_dns */,
+        nullptr /* factory_override */);
     CreateWebUIURLLoaderBinding(frame_tree_node->current_frame_host(), scheme,
                                 std::move(factory_receiver));
   }
@@ -1353,7 +1354,7 @@
         ContentBrowserClient::URLLoaderFactoryType::kNavigation, url::Origin(),
         frame_tree_node->navigation_request()->GetNavigationId(),
         &factory_receiver, &header_client, &bypass_redirect_checks,
-        nullptr /* factory_override */);
+        nullptr /* disable_secure_dns */, nullptr /* factory_override */);
     if (devtools_instrumentation::WillCreateURLLoaderFactory(
             frame_tree_node->current_frame_host(), true /* is_navigation */,
             false /* is_download */, &factory_receiver)) {
@@ -1553,7 +1554,8 @@
       ContentBrowserClient::URLLoaderFactoryType::kNavigation, url::Origin(),
       frame_tree_node->navigation_request()->GetNavigationId(),
       &factory_receiver, nullptr /* header_client */,
-      nullptr /* bypass_redirect_checks */, nullptr /* factory_override */);
+      nullptr /* bypass_redirect_checks */, nullptr /* disable_secure_dns */,
+      nullptr /* factory_override */);
   it->second->Clone(std::move(factory_receiver));
 }
 
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 85f2e6e..96bf3f5 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -511,18 +511,16 @@
   EXPECT_EQ(kUrl, observer.last_navigation_url());
   EXPECT_TRUE(observer.last_navigation_succeeded());
 
-  std::unique_ptr<ConsoleObserverDelegate> console_delegate(
-      new ConsoleObserverDelegate(
-          shell()->web_contents(),
-          "Not allowed to load local resource: view-source:about:blank"));
-  shell()->web_contents()->SetDelegate(console_delegate.get());
+  WebContentsConsoleObserver console_observer(shell()->web_contents());
+  console_observer.SetPattern(
+      "Not allowed to load local resource: view-source:about:blank");
 
   bool success = false;
   EXPECT_TRUE(ExecuteScriptAndExtractBool(
       shell()->web_contents(),
       "window.domAutomationController.send(clickViewSourceLink());", &success));
   EXPECT_TRUE(success);
-  console_delegate->Wait();
+  console_observer.Wait();
   // Original page shouldn't navigate away.
   EXPECT_EQ(kUrl, shell()->web_contents()->GetURL());
   EXPECT_FALSE(shell()
@@ -541,11 +539,9 @@
   EXPECT_EQ(kUrl, observer.last_navigation_url());
   EXPECT_TRUE(observer.last_navigation_succeeded());
 
-  std::unique_ptr<ConsoleObserverDelegate> console_delegate(
-      new ConsoleObserverDelegate(
-          shell()->web_contents(),
-          "Not allowed to load local resource: googlechrome://"));
-  shell()->web_contents()->SetDelegate(console_delegate.get());
+  WebContentsConsoleObserver console_observer(shell()->web_contents());
+  console_observer.SetPattern(
+      "Not allowed to load local resource: googlechrome://");
 
   bool success = false;
   EXPECT_TRUE(ExecuteScriptAndExtractBool(
@@ -553,7 +549,7 @@
       "window.domAutomationController.send(clickGoogleChromeLink());",
       &success));
   EXPECT_TRUE(success);
-  console_delegate->Wait();
+  console_observer.Wait();
   // Original page shouldn't navigate away.
   EXPECT_EQ(kUrl, shell()->web_contents()->GetURL());
 }
@@ -1511,14 +1507,12 @@
   GURL url(embedded_test_server()->GetURL("/title1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), url));
 
-  std::unique_ptr<ConsoleObserverDelegate> console_delegate(
-      new ConsoleObserverDelegate(
-          shell()->web_contents(),
-          "Throttling navigation to prevent the browser from hanging. See "
-          "https://crbug.com/882238. Command line switch "
-          "--disable-ipc-flooding-protection can be used to bypass the "
-          "protection"));
-  shell()->web_contents()->SetDelegate(console_delegate.get());
+  WebContentsConsoleObserver console_observer(shell()->web_contents());
+  console_observer.SetPattern(
+      "Throttling navigation to prevent the browser from hanging. See "
+      "https://crbug.com/882238. Command line switch "
+      "--disable-ipc-flooding-protection can be used to bypass the "
+      "protection");
 
   EXPECT_TRUE(ExecuteScript(shell(), R"(
     for(let i = 0; i<1000; ++i) {
@@ -1527,7 +1521,7 @@
     }
   )"));
 
-  console_delegate->Wait();
+  console_observer.Wait();
 }
 
 // Ensure the renderer process doesn't send too many IPC to the browser process
@@ -1540,14 +1534,12 @@
   GURL url(embedded_test_server()->GetURL("/title1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), url));
 
-  std::unique_ptr<ConsoleObserverDelegate> console_delegate(
-      new ConsoleObserverDelegate(
-          shell()->web_contents(),
-          "Throttling navigation to prevent the browser from hanging. See "
-          "https://crbug.com/882238. Command line switch "
-          "--disable-ipc-flooding-protection can be used to bypass the "
-          "protection"));
-  shell()->web_contents()->SetDelegate(console_delegate.get());
+  WebContentsConsoleObserver console_observer(shell()->web_contents());
+  console_observer.SetPattern(
+      "Throttling navigation to prevent the browser from hanging. See "
+      "https://crbug.com/882238. Command line switch "
+      "--disable-ipc-flooding-protection can be used to bypass the "
+      "protection");
 
   EXPECT_TRUE(ExecuteScript(shell(), R"(
     for(let i = 0; i<1000; ++i) {
@@ -1556,7 +1548,7 @@
     }
   )"));
 
-  console_delegate->Wait();
+  console_observer.Wait();
 }
 
 // TODO(http://crbug.com/632514): This test currently expects opener downloads
@@ -2435,46 +2427,48 @@
   GURL url_a = embedded_test_server()->GetURL("a.com", "/main_document");
   GURL url_b = embedded_test_server()->GetURL("a.com", "/title1.html");
 
-  auto console_delegate_1 = std::make_unique<ConsoleObserverDelegate>(
-      shell()->web_contents(), "Refused to execute inline script *");
-  shell()->web_contents()->SetDelegate(console_delegate_1.get());
+  {
+    WebContentsConsoleObserver console_observer(shell()->web_contents());
+    console_observer.SetPattern("Refused to execute inline script *");
 
-  // 1) Load main document with CSP: script-src 'none'
-  // 2) Open an about:srcdoc iframe. It inherits the CSP from its parent.
-  shell()->LoadURL(url_a);
-  main_document_response.WaitForRequest();
-  main_document_response.Send(
-      "HTTP/1.1 200 OK\n"
-      "content-type: text/html; charset=UTF-8\n"
-      "Content-Security-Policy: script-src 'none'\n"
-      "\n"
-      "<iframe name='theiframe' srcdoc='"
-      "  <script>"
-      "    console.error(\"CSP failure\");"
-      "  </script>"
-      "'>"
-      "</iframe>");
-  main_document_response.Done();
-  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+    // 1) Load main document with CSP: script-src 'none'
+    // 2) Open an about:srcdoc iframe. It inherits the CSP from its parent.
+    shell()->LoadURL(url_a);
+    main_document_response.WaitForRequest();
+    main_document_response.Send(
+        "HTTP/1.1 200 OK\n"
+        "content-type: text/html; charset=UTF-8\n"
+        "Content-Security-Policy: script-src 'none'\n"
+        "\n"
+        "<iframe name='theiframe' srcdoc='"
+        "  <script>"
+        "    console.error(\"CSP failure\");"
+        "  </script>"
+        "'>"
+        "</iframe>");
+    main_document_response.Done();
+    EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
 
-  // Check Javascript was blocked the first time.
-  console_delegate_1->Wait();
+    // Check Javascript was blocked the first time.
+    console_observer.Wait();
+  }
 
   // 3) The iframe navigates elsewhere.
   shell()->LoadURLForFrame(url_b, "theiframe",
                            ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
   EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
 
-  auto console_delegate_2 = std::make_unique<ConsoleObserverDelegate>(
-      shell()->web_contents(), "Refused to execute inline script *");
-  shell()->web_contents()->SetDelegate(console_delegate_2.get());
+  {
+    WebContentsConsoleObserver console_observer(shell()->web_contents());
+    console_observer.SetPattern("Refused to execute inline script *");
 
-  // 4) The iframe navigates back to about:srcdoc.
-  shell()->web_contents()->GetController().GoBack();
-  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+    // 4) The iframe navigates back to about:srcdoc.
+    shell()->web_contents()->GetController().GoBack();
+    EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
 
-  // Check Javascript was blocked the second time.
-  console_delegate_2->Wait();
+    // Check Javascript was blocked the second time.
+    console_observer.Wait();
+  }
 }
 
 IN_PROC_BROWSER_TEST_F(NavigationBaseBrowserTest,
@@ -2487,46 +2481,48 @@
   GURL url_a = embedded_test_server()->GetURL("a.com", "/main_document");
   GURL url_b = embedded_test_server()->GetURL("b.com", "/title1.html");
 
-  auto console_delegate_1 = std::make_unique<ConsoleObserverDelegate>(
-      shell()->web_contents(), "Refused to execute inline script *");
-  shell()->web_contents()->SetDelegate(console_delegate_1.get());
+  {
+    WebContentsConsoleObserver console_observer(shell()->web_contents());
+    console_observer.SetPattern("Refused to execute inline script *");
 
-  // 1) Load main document with CSP: script-src 'none'
-  // 2) Open an about:srcdoc iframe. It inherits the CSP from its parent.
-  shell()->LoadURL(url_a);
-  main_document_response.WaitForRequest();
-  main_document_response.Send(
-      "HTTP/1.1 200 OK\n"
-      "content-type: text/html; charset=UTF-8\n"
-      "Content-Security-Policy: script-src 'none'\n"
-      "\n"
-      "<iframe name='theiframe' srcdoc='"
-      "  <script>"
-      "    console.error(\"CSP failure\");"
-      "  </script>"
-      "'>"
-      "</iframe>");
-  main_document_response.Done();
-  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+    // 1) Load main document with CSP: script-src 'none'
+    // 2) Open an about:srcdoc iframe. It inherits the CSP from its parent.
+    shell()->LoadURL(url_a);
+    main_document_response.WaitForRequest();
+    main_document_response.Send(
+        "HTTP/1.1 200 OK\n"
+        "content-type: text/html; charset=UTF-8\n"
+        "Content-Security-Policy: script-src 'none'\n"
+        "\n"
+        "<iframe name='theiframe' srcdoc='"
+        "  <script>"
+        "    console.error(\"CSP failure\");"
+        "  </script>"
+        "'>"
+        "</iframe>");
+    main_document_response.Done();
+    EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
 
-  // Check Javascript was blocked the first time.
-  console_delegate_1->Wait();
+    // Check Javascript was blocked the first time.
+    console_observer.Wait();
+  }
 
   // 3) The iframe navigates elsewhere.
   shell()->LoadURLForFrame(url_b, "theiframe",
                            ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
   EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
 
-  auto console_delegate_2 = std::make_unique<ConsoleObserverDelegate>(
-      shell()->web_contents(), "Refused to execute inline script *");
-  shell()->web_contents()->SetDelegate(console_delegate_2.get());
+  {
+    WebContentsConsoleObserver console_observer(shell()->web_contents());
+    console_observer.SetPattern("Refused to execute inline script *");
 
-  // 4) The iframe navigates back to about:srcdoc.
-  shell()->web_contents()->GetController().GoBack();
-  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+    // 4) The iframe navigates back to about:srcdoc.
+    shell()->web_contents()->GetController().GoBack();
+    EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
 
-  // Check Javascript was blocked the second time.
-  console_delegate_2->Wait();
+    // Check Javascript was blocked the second time.
+    console_observer.Wait();
+  }
 }
 
 // Tests for cookies. Provides an HTTPS server.
@@ -2952,22 +2948,24 @@
             sub_document_1->GetSiteInstance());
 
   // 1. Writing a cookie inside a data-URL document is forbidden.
-  auto console_delegate_1 = std::make_unique<ConsoleObserverDelegate>(
-      shell()->web_contents(),
-      "*Failed to set the 'cookie' property on 'Document': Cookies are "
-      "disabled inside 'data:' URLs.*");
-  shell()->web_contents()->SetDelegate(console_delegate_1.get());
-  ExecuteScriptAsync(sub_document_1, "document.cookie = 'a=0';");
-  console_delegate_1->Wait();
+  {
+    WebContentsConsoleObserver console_observer(shell()->web_contents());
+    console_observer.SetPattern(
+        "*Failed to set the 'cookie' property on 'Document': Cookies are "
+        "disabled inside 'data:' URLs.*");
+    ExecuteScriptAsync(sub_document_1, "document.cookie = 'a=0';");
+    console_observer.Wait();
+  }
 
   // 2. Reading a cookie inside a data-URL document is forbidden.
-  auto console_delegate_2 = std::make_unique<ConsoleObserverDelegate>(
-      shell()->web_contents(),
-      "*Failed to read the 'cookie' property from 'Document': Cookies are "
-      "disabled inside 'data:' URLs.*");
-  shell()->web_contents()->SetDelegate(console_delegate_2.get());
-  ExecuteScriptAsync(sub_document_1, "document.cookie");
-  console_delegate_2->Wait();
+  {
+    WebContentsConsoleObserver console_observer(shell()->web_contents());
+    console_observer.SetPattern(
+        "*Failed to read the 'cookie' property from 'Document': Cookies are "
+        "disabled inside 'data:' URLs.*");
+    ExecuteScriptAsync(sub_document_1, "document.cookie");
+    console_observer.Wait();
+  }
 
   // 3. Set cookie in the main document. No cookies are sent when requested from
   // the data-URL.
@@ -2992,22 +2990,24 @@
             sub_document_2->GetSiteInstance());
 
   // 5. Writing a cookie inside a data-URL document is still forbidden.
-  auto console_delegate_3 = std::make_unique<ConsoleObserverDelegate>(
-      shell()->web_contents(),
-      "*Failed to set the 'cookie' property on 'Document': Cookies are "
-      "disabled inside 'data:' URLs.*");
-  shell()->web_contents()->SetDelegate(console_delegate_3.get());
-  ExecuteScriptAsync(sub_document_2, "document.cookie = 'c=0';");
-  console_delegate_3->Wait();
+  {
+    WebContentsConsoleObserver console_observer(shell()->web_contents());
+    console_observer.SetPattern(
+        "*Failed to set the 'cookie' property on 'Document': Cookies are "
+        "disabled inside 'data:' URLs.*");
+    ExecuteScriptAsync(sub_document_2, "document.cookie = 'c=0';");
+    console_observer.Wait();
+  }
 
   // 6. Reading a cookie inside a data-URL document is still forbidden.
-  auto console_delegate_4 = std::make_unique<ConsoleObserverDelegate>(
-      shell()->web_contents(),
-      "*Failed to read the 'cookie' property from 'Document': Cookies are "
-      "disabled inside 'data:' URLs.*");
-  shell()->web_contents()->SetDelegate(console_delegate_4.get());
-  ExecuteScriptAsync(sub_document_2, "document.cookie");
-  console_delegate_4->Wait();
+  {
+    WebContentsConsoleObserver console_observer(shell()->web_contents());
+    console_observer.SetPattern(
+        "*Failed to read the 'cookie' property from 'Document': Cookies are "
+        "disabled inside 'data:' URLs.*");
+    ExecuteScriptAsync(sub_document_2, "document.cookie");
+    console_observer.Wait();
+  }
 
   // 7. No cookies are sent when requested from the data-URL.
   GURL url_response_2 = https_server()->GetURL("a.com", "/response_2");
diff --git a/content/browser/net/network_quality_observer_impl.cc b/content/browser/net/network_quality_observer_impl.cc
index 6aecc43..07ee615 100644
--- a/content/browser/net/network_quality_observer_impl.cc
+++ b/content/browser/net/network_quality_observer_impl.cc
@@ -130,8 +130,9 @@
 
   bool network_quality_meaningfully_changed =
       http_rtt_changed || transport_rtt_changed || kbps_changed;
-  UMA_HISTOGRAM_BOOLEAN("NQE.ContentObserver.NetworkQualityMeaningfullyChanged",
-                        network_quality_meaningfully_changed);
+  LOCAL_HISTOGRAM_BOOLEAN(
+      "NQE.ContentObserver.NetworkQualityMeaningfullyChanged",
+      network_quality_meaningfully_changed);
 
   if (!network_quality_meaningfully_changed) {
     // Return since none of the metrics changed meaningfully. This reduces
diff --git a/content/browser/renderer_host/compositor_dependencies_android.cc b/content/browser/renderer_host/compositor_dependencies_android.cc
index a9bb7e4..3ce85212 100644
--- a/content/browser/renderer_host/compositor_dependencies_android.cc
+++ b/content/browser/renderer_host/compositor_dependencies_android.cc
@@ -13,8 +13,6 @@
 #include "base/time/time.h"
 #include "cc/raster/single_thread_task_graph_runner.h"
 #include "components/viz/client/frame_eviction_manager.h"
-#include "components/viz/common/features.h"
-#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/compositor/surface_utils.h"
 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
@@ -82,17 +80,13 @@
     : frame_sink_id_allocator_(kDefaultClientId) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  bool enable_viz = features::IsVizDisplayCompositorEnabled();
-  if (!enable_viz) {
-    // The SharedBitmapManager can be null as software compositing is not
-    // supported or used on Android.
-    frame_sink_manager_impl_ = std::make_unique<viz::FrameSinkManagerImpl>(
-        /*shared_bitmap_manager=*/nullptr);
-    surface_utils::ConnectWithLocalFrameSinkManager(
-        &host_frame_sink_manager_, frame_sink_manager_impl_.get());
-  } else {
-    CreateVizFrameSinkManager();
-  }
+  // Set up a callback to automatically re-connect if we lose our connection.
+  // Unretained is safe due to base::NoDestructor.
+  host_frame_sink_manager_.SetConnectionLostCallback(base::BindRepeating(
+      &CompositorDependenciesAndroid::CreateVizFrameSinkManager,
+      base::Unretained(this)));
+
+  CreateVizFrameSinkManager();
 }
 
 CompositorDependenciesAndroid::~CompositorDependenciesAndroid() = default;
@@ -113,12 +107,6 @@
       std::move(frame_sink_manager_client_receiver),
       base::ThreadTaskRunnerHandle::Get(), std::move(frame_sink_manager));
 
-  // Set up a callback to automatically re-connect if we lose our
-  // connection.
-  host_frame_sink_manager_.SetConnectionLostCallback(base::BindRepeating([]() {
-    CompositorDependenciesAndroid::Get().CreateVizFrameSinkManager();
-  }));
-
   // Set up a pending request which will be run once we've successfully
   // connected to the GPU process.
   pending_connect_viz_on_io_thread_ = base::BindOnce(
diff --git a/content/browser/renderer_host/compositor_dependencies_android.h b/content/browser/renderer_host/compositor_dependencies_android.h
index d31f4a7..a9259b2 100644
--- a/content/browser/renderer_host/compositor_dependencies_android.h
+++ b/content/browser/renderer_host/compositor_dependencies_android.h
@@ -21,10 +21,6 @@
 class TaskGraphRunner;
 }  // namespace cc
 
-namespace viz {
-class FrameSinkManagerImpl;
-}  // namespace viz
-
 namespace content {
 
 class CompositorImpl;
@@ -39,10 +35,6 @@
     return &host_frame_sink_manager_;
   }
 
-  viz::FrameSinkManagerImpl* frame_sink_manager_impl() {
-    return frame_sink_manager_impl_.get();
-  }
-
   viz::FrameSinkId AllocateFrameSinkId();
   void TryEstablishVizConnectionIfNeeded();
   void OnCompositorVisible(CompositorImpl* compositor);
@@ -66,14 +58,6 @@
   viz::HostFrameSinkManager host_frame_sink_manager_;
   viz::FrameSinkIdAllocator frame_sink_id_allocator_;
 
-  // Non-viz members:
-  // This is owned here so that SurfaceManager will be accessible in process
-  // when display is in the same process. Other than using SurfaceManager,
-  // access to |in_process_frame_sink_manager_| should happen via
-  // |host_frame_sink_manager_| instead which uses Mojo. See
-  // http://crbug.com/657959.
-  std::unique_ptr<viz::FrameSinkManagerImpl> frame_sink_manager_impl_;
-
   // A task which runs cleanup tasks on low-end Android after a delay. Enqueued
   // when we hide, canceled when we're shown.
   base::CancelableOnceClosure low_end_background_cleanup_task_;
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 5dfad8e..0aa5915 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -268,7 +268,6 @@
       needs_animate_(false),
       pending_frames_(0U),
       layer_tree_frame_sink_request_pending_(false) {
-  CHECK(features::IsVizDisplayCompositorEnabled());
   DCHECK(client);
 
   SetRootWindow(root_window);
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index 51b8dcc..b8b0896 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -1065,7 +1065,8 @@
       rph->GetBrowserContext(), nullptr /* frame_host */, rph->GetID(),
       factory_type, origin, base::nullopt /* navigation_id */,
       &default_factory_receiver, &factory_params->header_client,
-      &bypass_redirect_checks, &factory_params->factory_override);
+      &bypass_redirect_checks, nullptr /* disable_secure_dns */,
+      &factory_params->factory_override);
   devtools_instrumentation::WillCreateURLLoaderFactoryForServiceWorker(
       rph, routing_id, &default_factory_receiver);
 
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index da7db7c..4dbda3c 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -1871,6 +1871,7 @@
       ContentBrowserClient::URLLoaderFactoryType::kServiceWorkerScript,
       url::Origin::Create(scope), /*navigation_id=*/base::nullopt,
       &pending_receiver, &header_client, &bypass_redirect_checks,
+      /*disable_secure_dns=*/nullptr,
       /*factory_override=*/nullptr);
   if (header_client) {
     NavigationURLLoaderImpl::CreateURLLoaderFactoryWithHeaderClient(
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index 764cd1d..fa20fa3 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -328,7 +328,7 @@
       ContentBrowserClient::URLLoaderFactoryType::kNavigation, url::Origin(),
       frame_tree_node->navigation_request()->GetNavigationId(), &receiver,
       &header_client, &bypass_redirect_checks_unused,
-      /*factory_override=*/nullptr);
+      /*disable_secure_dns=*/nullptr, /*factory_override=*/nullptr);
 
   // Make the network factory.
   NavigationURLLoaderImpl::CreateURLLoaderFactoryWithHeaderClient(
diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc
index f8fbae0..ec4d682 100644
--- a/content/browser/worker_host/dedicated_worker_host.cc
+++ b/content/browser/worker_host/dedicated_worker_host.cc
@@ -301,7 +301,7 @@
       ContentBrowserClient::URLLoaderFactoryType::kWorkerSubResource, origin_,
       /*navigation_id=*/base::nullopt, &default_factory_receiver,
       &factory_params->header_client, bypass_redirect_checks,
-      &factory_params->factory_override);
+      /*disable_secure_dns=*/nullptr, &factory_params->factory_override);
 
   // TODO(nhiroki): Call devtools_instrumentation::WillCreateURLLoaderFactory()
   // here.
diff --git a/content/browser/worker_host/shared_worker_host.cc b/content/browser/worker_host/shared_worker_host.cc
index bc4f340..2819b9c5 100644
--- a/content/browser/worker_host/shared_worker_host.cc
+++ b/content/browser/worker_host/shared_worker_host.cc
@@ -268,7 +268,7 @@
       ContentBrowserClient::URLLoaderFactoryType::kWorkerSubResource, origin,
       /*navigation_id=*/base::nullopt, &default_factory_receiver,
       &factory_params->header_client, bypass_redirect_checks,
-      &factory_params->factory_override);
+      /*disable_secure_dns=*/nullptr, &factory_params->factory_override);
 
   // TODO(nhiroki): Call devtools_instrumentation::WillCreateURLLoaderFactory()
   // here.
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.cc b/content/browser/worker_host/worker_script_fetch_initiator.cc
index c3d4948..dc51bc2 100644
--- a/content/browser/worker_host/worker_script_fetch_initiator.cc
+++ b/content/browser/worker_host/worker_script_fetch_initiator.cc
@@ -326,7 +326,7 @@
         request_initiator,
         /*navigation_id=*/base::nullopt, &default_factory_receiver,
         &factory_params->header_client, &bypass_redirect_checks,
-        &factory_params->factory_override);
+        nullptr /* disable_secure_dns */, &factory_params->factory_override);
     factory_bundle_for_browser_info->set_bypass_redirect_checks(
         bypass_redirect_checks);
 
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 591d9f7..074b20a 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -744,6 +744,7 @@
     mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
         header_client,
     bool* bypass_redirect_checks,
+    bool* disable_secure_dns,
     network::mojom::URLLoaderFactoryOverridePtr* factory_override) {
   DCHECK(browser_context);
   return false;
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index dd0f376..cbe040b6 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -1314,6 +1314,10 @@
   // |bypass_redirect_checks| will be set to true when the embedder will be
   // handling redirect security checks.
   //
+  // |disable_secure_dns| will be set to true when the URLLoaderFactory will be
+  // used exclusively within a window that requires secure DNS to be turned off,
+  // such as a window created for captive portal resolution.
+  //
   // |factory_override| gives the embedder a chance to replace the network
   // service's "internal" URLLoaderFactory. See more details in the
   // documentation for URLLoaderFactoryOverride in network_context.mojom.
@@ -1343,6 +1347,7 @@
       mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
           header_client,
       bool* bypass_redirect_checks,
+      bool* disable_secure_dns,
       network::mojom::URLLoaderFactoryOverridePtr* factory_override);
 
   // Returns true when the embedder wants to intercept a websocket connection.
diff --git a/content/public/test/test_launcher.cc b/content/public/test/test_launcher.cc
index 79cf5ad..76c0711 100644
--- a/content/public/test/test_launcher.cc
+++ b/content/public/test/test_launcher.cc
@@ -116,11 +116,7 @@
           "    Sets the total number of shards to N.\n"
           "\n"
           "  --test-launcher-shard-index=N\n"
-          "    Sets the shard index to run to N (from 0 to TOTAL - 1).\n"
-          "\n"
-          "  --test-launcher-print-temp-leaks\n"
-          "    Prints information about leaked files and/or directories in\n"
-          "    child process's temporary directories (Windows and macOS).\n");
+          "    Sets the shard index to run to N (from 0 to TOTAL - 1).\n");
 }
 
 // Implementation of base::TestLauncherDelegate. This is also a test launcher,
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index ae127c2..20262e05 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -1421,7 +1421,7 @@
   render_view->render_widget_ = RenderWidget::CreateForFrame(
       params->main_frame_widget_routing_id, compositor_deps,
       params->visual_properties.display_mode,
-      /*is_undead=*/false, params->never_visible);
+      /*is_undead=*/false, render_view->widgets_never_visible());
 
   RenderWidget* render_widget = render_view->GetWidget();
   render_widget->set_delegate(render_view);
@@ -1600,16 +1600,10 @@
       // time a local main frame was created.
       //
       // This block of code mimics RenderFrameImpl::CreateMainFrame().
-      //
-      // Note that |never_visible| is not provided by the browser in this path
-      // which means that a |never_visible| local main frame navigation to the
-      // origin of an OOP child frame could result in losing the |never_visible|
-      // state. We need |never_visible| to be a property of the RenderView so
-      // that future frames can see it.
       render_view->render_widget_ = RenderWidget::CreateForFrame(
           widget_params->routing_id, compositor_deps,
           widget_params->visual_properties.display_mode,
-          /*is_undead=*/false, /*never_visible=*/false);
+          /*is_undead=*/false, render_view->widgets_never_visible());
 
       render_widget = render_view->GetWidget();
       render_widget->set_delegate(render_view);
@@ -1650,9 +1644,8 @@
     // space/context.
     std::unique_ptr<RenderWidget> render_widget = RenderWidget::CreateForFrame(
         widget_params->routing_id, compositor_deps,
-        // TODO(danakj): Use widget_params->visual_properties.screen_info here?
-        blink::mojom::DisplayMode::kUndefined,
-        /*is_undead=*/false, /*never_visible=*/false);
+        widget_params->visual_properties.display_mode,
+        /*is_undead=*/false, render_view->widgets_never_visible());
 
     // Non-owning pointer that is self-referencing and destroyed by calling
     // Close(). We use the new RenderWidget as the client for this
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 9725651..b546a27 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -440,6 +440,7 @@
     : routing_id_(params.view_id),
       renderer_wide_named_frame_lookup_(
           params.renderer_wide_named_frame_lookup),
+      widgets_never_visible_(params.never_visible),
       compositor_deps_(compositor_deps),
       webkit_preferences_(params.web_preferences),
       session_storage_namespace_id_(params.session_storage_namespace_id) {
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 8698972c..e57f2d48 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -140,6 +140,15 @@
   blink::WebView* webview();
   const blink::WebView* webview() const;
 
+  // When true, a hint to all RenderWidgets that they will never be
+  // user-visible. This is separate from page visibility, as background pages
+  // can be marked visible in blink even though they are not user-visible.
+  // Page visibility controls blink behaviour for javascript, timers, and
+  // such to inform blink it is in the foreground or background. Whereas this
+  // bit refers to user-visibility and whether the tab needs to produce pixels
+  // to put on the screen at some point or not.
+  bool widgets_never_visible() const { return widgets_never_visible_; }
+
   // Returns the RenderWidget owned by this RenderView. Can be nullptr if the
   // RenderView does not own a RenderWidget [e.g. for remote main frame in
   // future].
@@ -549,6 +558,15 @@
   // beyond the usual opener-relationship-based BrowsingInstance boundaries).
   const bool renderer_wide_named_frame_lookup_;
 
+  // A value provided by the browser to state that all RenderWidgets in this
+  // RenderView's frame tree will never be user-visible. This is separate from
+  // Page visibility, as non-user-visible pages can still be marked visible for
+  // blink. Page visibility controls blink behaviour for javascript, timers, and
+  // such to inform blink it is in the foreground or background. Whereas this
+  // bit refers to user-visibility and whether the tab needs to produce pixels
+  // to put on the screen at some point or not.
+  const bool widgets_never_visible_;
+
   // Dependency injection for RenderWidget and compositing to inject behaviour
   // and not depend on RenderThreadImpl in tests.
   CompositorDependencies* const compositor_deps_;
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
index 1c3ddef..ef61138 100644
--- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
+++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
@@ -31,6 +31,7 @@
         boolean isBrowserProcess = !ContextUtils.getProcessName().contains(":");
         ContextUtils.initApplicationContext(this);
         ResourceBundle.setNoAvailableLocalePaks();
+        LibraryLoader.getInstance().enableJniChecks();
         LibraryLoader.getInstance().setLibraryProcessType(isBrowserProcess
                         ? LibraryProcessType.PROCESS_BROWSER
                         : LibraryProcessType.PROCESS_CHILD);
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index d83b964..5ebf5c3 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1483,6 +1483,9 @@
     "../browser/accessibility/browser_accessibility_unittest.cc",
     "../browser/accessibility/browser_accessibility_win_unittest.cc",
     "../browser/accessibility/one_shot_accessibility_tree_search_unittest.cc",
+    "../browser/appcache/appcache_cache_test_helper.cc",
+    "../browser/appcache/appcache_cache_test_helper.h",
+    "../browser/appcache/appcache_cache_test_helper_unittest.cc",
     "../browser/appcache/appcache_database_unittest.cc",
     "../browser/appcache/appcache_disk_cache_unittest.cc",
     "../browser/appcache/appcache_group_unittest.cc",
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index a92d5ff6..7178258 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -199,8 +199,8 @@
 # Produces blank images on Intel HD 630 w/ Mesa 19.0.2
 crbug.com/976861 [ linux intel-0x5912 ] Pixel_OffscreenCanvasTransferToImageBitmap [ Skip ]
 
-# Flakily produces a ~50% blank image
-crbug.com/983600 [ mojave amd-0x6821 ] Pixel_CSSFilterEffects_NoOverlays [ RetryOnFailure ]
+# Flakes regularly on Mac.
+crbug.com/1040202 [ mac ] Pixel_CSSFilterEffects_NoOverlays [ Failure ]
 
 # Skip swap chain tests on non-Windows
 [ android ] Pixel_CanvasLowLatency2DSwapChain [ Skip ]
diff --git a/content/test/url_loader_interceptor_test.cc b/content/test/url_loader_interceptor_test.cc
index edca426f..3079878 100644
--- a/content/test/url_loader_interceptor_test.cc
+++ b/content/test/url_loader_interceptor_test.cc
@@ -169,6 +169,7 @@
       mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
           header_client,
       bool* bypass_redirect_checks,
+      bool* disable_secure_dns,
       network::mojom::URLLoaderFactoryOverridePtr* factory_override) override {
     if (header_client)
       receivers_.Add(this, header_client->InitWithNewPipeAndPassReceiver());
diff --git a/docs/webui_in_components.md b/docs/webui_in_components.md
index 1734726..006f3f7 100644
--- a/docs/webui_in_components.md
+++ b/docs/webui_in_components.md
@@ -85,6 +85,12 @@
 </grit-part>
 ```
 
+Add the created file in `components/resources/dev_ui_components_resources.grd`:
+
+```xml
++<part file="hello_world_resources.grdp" />
+```
+
 ## Adding URL constants for the new chrome URL
 
 Create the `constants.cc` and `constants.h` files to add the URL constants. This is where you will add the URL or URL's which will be directed to your new resources.
@@ -148,8 +154,8 @@
 ```c++
 #include "components/hello_world/hello_world_ui.h"
 
-#include "components/grit/components_resources.h"
 #include "components/grit/components_scaled_resources.h"
+#include "components/grit/dev_ui_components_resources.h"
 #include "components/hello_world/constants.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/browser_context.h"
@@ -199,9 +205,9 @@
 and `src/components/hello_world/DEPS:`
 ```
 include_rules = [
-  "+components/grit/components_resources.h",
   "+components/strings/grit/components_strings.h",
   "+components/grit/components_scaled_resources.h"
+  "+components/grit/dev_ui_components_resources.h",
 ]
 ```
 
@@ -300,6 +306,11 @@
 
 Some pages have many messages or share code that sends messages. To make possible message handling and/or to create a WebUI dialogue `c++->js` and `js->c++`, follow the guide in [WebUI Explainer](https://chromium.googlesource.com/chromium/src/+/master/docs/webui_explainer.md).
 
+## DevUI Pages
+
+DevUI pages are WebUI pages intended for developers, and unlikely used by most users. An example is `chrome://bluetooth-internals`. On Android Chrome, these pages are moved to a separate [Dynamic Feature Module (DFM)](https://chromium.googlesource.com/chromium/src/+/master/docs/android_dynamic_feature_modules.md) to reduce binary size. Most WebUI pages are DevUI. This is why in this doc uses `dev_ui_components_resources.{grd, h}` in its examples.
+
+`components/` resources that are intended for end users are associated with `components_resources.{grd, h}` and `components_scaled_resorces.{grd, h}`. Use these in place of or inadditional to `dev_ui_components_resources.{grd, h}` if needed.
 
 <script>
 let nameEls = Array.from(document.querySelectorAll('[id], a[name]'));
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc
index 45026e8..f125c9cd 100644
--- a/extensions/browser/extension_prefs.cc
+++ b/extensions/browser/extension_prefs.cc
@@ -194,6 +194,10 @@
 // A list of installed ids and a signature.
 constexpr const char kInstallSignature[] = "extensions.install_signature";
 
+// A list of IDs of external extensions that the user has chosen to uninstall;
+// saved as an indication to not re-install that extension.
+constexpr const char kExternalUninstalls[] = "extensions.external_uninstalls";
+
 // A boolean preference that indicates whether the extension should not be
 // synced. Default value is false.
 constexpr const char kPrefDoNotSync[] = "do_not_sync";
@@ -1161,7 +1165,9 @@
 
 bool ExtensionPrefs::IsExternalExtensionUninstalled(
     const std::string& id) const {
-  return DoesExtensionHaveState(id, Extension::EXTERNAL_EXTENSION_UNINSTALLED);
+  ExtensionIdList uninstalled_ids;
+  GetUserExtensionPrefIntoContainer(kExternalUninstalls, &uninstalled_ids);
+  return base::Contains(uninstalled_ids, id);
 }
 
 bool ExtensionPrefs::IsExtensionDisabled(const std::string& id) const {
@@ -1196,6 +1202,19 @@
     int install_flags,
     const std::string& install_parameter,
     const base::Optional<int>& dnr_ruleset_checksum) {
+  // If the extension was previously an external extension that was uninstalled,
+  // clear the external uninstall bit.
+  // TODO(devlin): We previously did this because we indicated external
+  // uninstallation through the extension dictionary itself (on the "state"
+  // key), and needed a way to have other installation - such as user or policy
+  // installations - override that state. Now that external uninstalls are
+  // stored separately, we shouldn't necessarily have to do this - a new install
+  // can still override the external uninstall without clearing the bit.
+  // However, it's not clear if existing subsystems may also be relying on this
+  // bit being set/unset. For now, maintain existing behavior.
+  if (IsExternalExtensionUninstalled(extension->id()))
+    ClearExternalUninstallBit(extension->id());
+
   ScopedExtensionPrefUpdate update(prefs_, extension->id());
   auto extension_dict = update.Get();
   const base::Time install_time = clock_->Now();
@@ -1218,15 +1237,11 @@
   // true, which signifies that the registry key was deleted or the pref file
   // no longer lists the extension).
   if (!external_uninstall && Manifest::IsExternalLocation(location)) {
-    UpdateExtensionPref(extension_id, kPrefState,
-                        std::make_unique<base::Value>(
-                            Extension::EXTERNAL_EXTENSION_UNINSTALLED));
-    extension_pref_value_map_->SetExtensionState(extension_id, false);
-    for (auto& observer : observer_list_)
-      observer.OnExtensionStateChanged(extension_id, false);
-  } else {
-    DeleteExtensionPrefs(extension_id);
+    ListPrefUpdate update(prefs_, kExternalUninstalls);
+    update->Append(extension_id);
   }
+
+  DeleteExtensionPrefs(extension_id);
 }
 
 void ExtensionPrefs::SetExtensionEnabled(const std::string& extension_id) {
@@ -1240,11 +1255,9 @@
 
 void ExtensionPrefs::SetExtensionDisabled(const std::string& extension_id,
                                           int disable_reasons) {
-  if (!IsExternalExtensionUninstalled(extension_id)) {
-    UpdateExtensionPref(extension_id, kPrefState,
-                        std::make_unique<base::Value>(Extension::DISABLED));
-    extension_pref_value_map_->SetExtensionState(extension_id, false);
-  }
+  UpdateExtensionPref(extension_id, kPrefState,
+                      std::make_unique<base::Value>(Extension::DISABLED));
+  extension_pref_value_map_->SetExtensionState(extension_id, false);
   UpdateExtensionPref(extension_id, kPrefDisableReasons,
                       std::make_unique<base::Value>(disable_reasons));
   for (auto& observer : observer_list_)
@@ -1354,8 +1367,10 @@
       !extensions->GetDictionaryWithoutPathExpansion(extension_id, &ext))
     return std::unique_ptr<ExtensionInfo>();
   int state_value;
+  // TODO(devlin): Remove this once all clients are updated with
+  // MigrateToNewExternalUninstallPref().
   if (ext->GetInteger(kPrefState, &state_value) &&
-      state_value == Extension::EXTERNAL_EXTENSION_UNINSTALLED) {
+      state_value == Extension::DEPRECATED_EXTERNAL_EXTENSION_UNINSTALLED) {
     return std::unique_ptr<ExtensionInfo>();
   }
 
@@ -1384,30 +1399,6 @@
   return extensions_info;
 }
 
-std::unique_ptr<ExtensionPrefs::ExtensionsInfo>
-ExtensionPrefs::GetUninstalledExtensionsInfo() const {
-  std::unique_ptr<ExtensionsInfo> extensions_info(new ExtensionsInfo);
-
-  const base::DictionaryValue* extensions =
-      prefs_->GetDictionary(pref_names::kExtensions);
-  for (base::DictionaryValue::Iterator extension_id(*extensions);
-       !extension_id.IsAtEnd(); extension_id.Advance()) {
-    const base::DictionaryValue* ext = NULL;
-    if (!crx_file::id_util::IdIsValid(extension_id.key()) ||
-        !IsExternalExtensionUninstalled(extension_id.key()) ||
-        !extension_id.value().GetAsDictionary(&ext))
-      continue;
-
-    std::unique_ptr<ExtensionInfo> info =
-        GetInstalledInfoHelper(extension_id.key(), ext,
-                               /*include_component_extensions = */ false);
-    if (info)
-      extensions_info->push_back(std::move(info));
-  }
-
-  return extensions_info;
-}
-
 void ExtensionPrefs::SetDelayedInstallInfo(
     const Extension* extension,
     Extension::State initial_state,
@@ -1874,7 +1865,7 @@
 }
 
 void ExtensionPrefs::ClearExternalUninstallForTesting(const ExtensionId& id) {
-  DeleteExtensionPrefs(id);
+  ClearExternalUninstallBit(id);
 }
 
 bool ExtensionPrefs::HasUserSeenExtensionsCheckupOnStartup() {
@@ -1915,6 +1906,8 @@
   InitPrefStore();
 
   MigrateToNewWithholdingPref();
+
+  MigrateToNewExternalUninstallPref();
 }
 
 AppSorting* ExtensionPrefs::app_sorting() const {
@@ -1948,6 +1941,7 @@
   registry->RegisterListPref(pref_names::kAllowedInstallSites);
   registry->RegisterStringPref(pref_names::kLastChromeVersion, std::string());
   registry->RegisterDictionaryPref(kInstallSignature);
+  registry->RegisterListPref(kExternalUninstalls);
 
   registry->RegisterListPref(pref_names::kNativeMessagingBlacklist);
   registry->RegisterListPref(pref_names::kNativeMessagingWhitelist);
@@ -2242,4 +2236,50 @@
   }
 }
 
+void ExtensionPrefs::MigrateToNewExternalUninstallPref() {
+  const base::Value* extensions =
+      prefs_->GetDictionary(pref_names::kExtensions);
+  if (!extensions)
+    return;
+
+  std::vector<std::string> uninstalled_ids;
+  for (const auto& item : extensions->DictItems()) {
+    if (!crx_file::id_util::IdIsValid(item.first) || !item.second.is_dict()) {
+      continue;
+    }
+
+    base::Optional<int> state_value = item.second.FindIntKey(kPrefState);
+    if (!state_value ||
+        *state_value != Extension::DEPRECATED_EXTERNAL_EXTENSION_UNINSTALLED) {
+      continue;
+    }
+    uninstalled_ids.push_back(item.first);
+  }
+
+  if (uninstalled_ids.empty())
+    return;
+
+  ListPrefUpdate update(prefs_, kExternalUninstalls);
+  base::Value* current_ids = update.Get();
+  for (const auto& id : uninstalled_ids) {
+    base::Value::ListStorage& list = current_ids->GetList();
+    auto existing_entry =
+        std::find_if(list.begin(), list.end(), [&id](const base::Value& value) {
+          return value.is_string() && value.GetString() == id;
+        });
+    if (existing_entry == list.end())
+      list.push_back(base::Value(id));
+
+    DeleteExtensionPrefs(id);
+  }
+}
+
+void ExtensionPrefs::ClearExternalUninstallBit(const ExtensionId& id) {
+  ListPrefUpdate update(prefs_, kExternalUninstalls);
+  base::Value* current_ids = update.Get();
+  base::EraseIf(current_ids->GetList(), [&id](const base::Value& value) {
+    return value.is_string() && value.GetString() == id;
+  });
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/extension_prefs.h b/extensions/browser/extension_prefs.h
index f0e6d14..82e792f 100644
--- a/extensions/browser/extension_prefs.h
+++ b/extensions/browser/extension_prefs.h
@@ -454,10 +454,6 @@
   std::unique_ptr<ExtensionsInfo> GetInstalledExtensionsInfo(
       bool include_component_extensions = false) const;
 
-  // Same as above, but only includes external extensions the user has
-  // explicitly uninstalled.
-  std::unique_ptr<ExtensionsInfo> GetUninstalledExtensionsInfo() const;
-
   // Returns the ExtensionInfo from the prefs for the given extension. If the
   // extension is not present, NULL is returned.
   std::unique_ptr<ExtensionInfo> GetInstalledExtensionInfo(
@@ -620,6 +616,12 @@
   // TODO(tjudkins): Remove this and the obsolete key in M83.
   void MigrateToNewWithholdingPref();
 
+  // Migrates to the new way of recording explicit user uninstalls of external
+  // extensions (by using a list of IDs rather than a bit set in each extension
+  // dictionary).
+  // TODO(devlin): Remove this once clients are migrated over, around M84.
+  void MigrateToNewExternalUninstallPref();
+
   // When called before the ExtensionService is created, alerts that are
   // normally suppressed in first run will still trigger.
   static void SetRunAlertsInFirstRunForTest();
@@ -789,6 +791,9 @@
   // for a given extension.
   bool HasWithholdingPermissionsSetting(const ExtensionId& extension_id) const;
 
+  // Clears the bit indicating that an external extension was uninstalled.
+  void ClearExternalUninstallBit(const ExtensionId& extension_id);
+
   content::BrowserContext* browser_context_;
 
   // The pref service specific to this set of extension prefs. Owned by the
diff --git a/extensions/common/extension.h b/extensions/common/extension.h
index eb535aeb..bee8d17 100644
--- a/extensions/common/extension.h
+++ b/extensions/common/extension.h
@@ -52,9 +52,11 @@
     DISABLED = 0,
     ENABLED = 1,
 
+    // DEPRECATED. External uninstallation bits are now stored directly in
+    // the ExtensionPrefs. See https://crbug.com/795026.
     // An external extension that the user uninstalled. We should not reinstall
     // such extensions on startup.
-    EXTERNAL_EXTENSION_UNINSTALLED = 2,
+    DEPRECATED_EXTERNAL_EXTENSION_UNINSTALLED = 2,
 
     // DEPRECATED: Special state for component extensions.
     // ENABLED_COMPONENT_DEPRECATED = 3,
diff --git a/extensions/shell/browser/shell_content_browser_client.cc b/extensions/shell/browser/shell_content_browser_client.cc
index 182dc53b..2c9c327 100644
--- a/extensions/shell/browser/shell_content_browser_client.cc
+++ b/extensions/shell/browser/shell_content_browser_client.cc
@@ -313,6 +313,7 @@
     mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
         header_client,
     bool* bypass_redirect_checks,
+    bool* disable_secure_dns,
     network::mojom::URLLoaderFactoryOverridePtr* factory_override) {
   auto* web_request_api =
       extensions::BrowserContextKeyedAPIFactory<extensions::WebRequestAPI>::Get(
diff --git a/extensions/shell/browser/shell_content_browser_client.h b/extensions/shell/browser/shell_content_browser_client.h
index ba5e219..8b1ba33 100644
--- a/extensions/shell/browser/shell_content_browser_client.h
+++ b/extensions/shell/browser/shell_content_browser_client.h
@@ -89,6 +89,7 @@
       mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
           header_client,
       bool* bypass_redirect_checks,
+      bool* disable_secure_dns,
       network::mojom::URLLoaderFactoryOverridePtr* factory_override) override;
   bool HandleExternalProtocol(
       const GURL& url,
diff --git a/extensions/test/extension_test_notification_observer.cc b/extensions/test/extension_test_notification_observer.cc
index 8256704..12d6d18 100644
--- a/extensions/test/extension_test_notification_observer.cc
+++ b/extensions/test/extension_test_notification_observer.cc
@@ -71,7 +71,6 @@
 ExtensionTestNotificationObserver::ExtensionTestNotificationObserver(
     content::BrowserContext* context)
     : context_(context),
-      extension_installs_observed_(0),
       extension_load_errors_observed_(0),
       crx_installers_done_observed_(0) {
   if (context_)
@@ -93,15 +92,6 @@
       .Wait();
 }
 
-bool ExtensionTestNotificationObserver::WaitForExtensionInstallError() {
-  int before = extension_installs_observed_;
-  content::WindowedNotificationObserver(
-      NOTIFICATION_EXTENSION_INSTALL_ERROR,
-      content::NotificationService::AllSources())
-      .Wait();
-  return extension_installs_observed_ == before;
-}
-
 bool ExtensionTestNotificationObserver::WaitForExtensionLoadError() {
   int before = extension_load_errors_observed_;
   WaitForNotification(NOTIFICATION_EXTENSION_LOAD_ERROR);
diff --git a/extensions/test/extension_test_notification_observer.h b/extensions/test/extension_test_notification_observer.h
index 55de83d..575d16e 100644
--- a/extensions/test/extension_test_notification_observer.h
+++ b/extensions/test/extension_test_notification_observer.h
@@ -34,10 +34,6 @@
   explicit ExtensionTestNotificationObserver(content::BrowserContext* context);
   ~ExtensionTestNotificationObserver() override;
 
-  // Wait for an extension install error to be raised. Returns true if an
-  // error was raised.
-  bool WaitForExtensionInstallError();
-
   // Waits for an extension load error. Returns true if the error really
   // happened.
   bool WaitForExtensionLoadError();
@@ -130,7 +126,6 @@
   std::unique_ptr<content::WindowedNotificationObserver> observer_;
 
   std::string last_loaded_extension_id_;
-  int extension_installs_observed_;
   int extension_load_errors_observed_;
   int crx_installers_done_observed_;
 
diff --git a/fuchsia/engine/browser/ax_tree_converter.cc b/fuchsia/engine/browser/ax_tree_converter.cc
index a35da0b..686b5015 100644
--- a/fuchsia/engine/browser/ax_tree_converter.cc
+++ b/fuchsia/engine/browser/ax_tree_converter.cc
@@ -15,66 +15,109 @@
 #include "ui/accessibility/ax_tree_id.h"
 #include "ui/gfx/geometry/rect_f.h"
 
+using fuchsia::accessibility::semantics::MAX_LABEL_SIZE;
+
 namespace {
 
 fuchsia::accessibility::semantics::Role ConvertRole(ax::mojom::Role role) {
-  if (role == ax::mojom::Role::kUnknown)
-    return fuchsia::accessibility::semantics::Role::UNKNOWN;
+  if (role == ax::mojom::Role::kButton)
+    return fuchsia::accessibility::semantics::Role::BUTTON;
+  if (role == ax::mojom::Role::kHeader)
+    return fuchsia::accessibility::semantics::Role::HEADER;
+  if (role == ax::mojom::Role::kImage)
+    return fuchsia::accessibility::semantics::Role::IMAGE;
+  if (role == ax::mojom::Role::kTextField)
+    return fuchsia::accessibility::semantics::Role::TEXT_FIELD;
 
-  // TODO(crbug.com/973095): Currently Fuchsia only has one Role option. Add
-  // more and update tests as they become supported.
   return fuchsia::accessibility::semantics::Role::UNKNOWN;
 }
 
-fuchsia::accessibility::semantics::Attributes SetAttributes(std::string name) {
+fuchsia::accessibility::semantics::Attributes ConvertAttributes(
+    const ui::AXNodeData& node) {
   fuchsia::accessibility::semantics::Attributes attributes;
-  attributes.set_label(name);
+  if (node.HasStringAttribute(ax::mojom::StringAttribute::kName)) {
+    const std::string& name =
+        node.GetStringAttribute(ax::mojom::StringAttribute::kName);
+    attributes.set_label(name.substr(0, MAX_LABEL_SIZE));
+  }
+
+  if (node.HasStringAttribute(ax::mojom::StringAttribute::kDescription)) {
+    const std::string& description =
+        node.GetStringAttribute(ax::mojom::StringAttribute::kDescription);
+    attributes.set_secondary_label(description.substr(0, MAX_LABEL_SIZE));
+  }
+
   return attributes;
 }
 
-std::vector<fuchsia::accessibility::semantics::Action> ConvertActions(
-    uint32_t actions) {
-  std::vector<fuchsia::accessibility::semantics::Action> fuchsia_actions;
-  ax::mojom::Action action_enum = static_cast<ax::mojom::Action>(actions);
+// This function handles conversions for all data that is part of a Semantic
+// Node's state. The corresponding data in an AXNodeData is stored in various
+// attributes.
+fuchsia::accessibility::semantics::States ConvertStates(
+    const ui::AXNodeData& node) {
+  fuchsia::accessibility::semantics::States states;
 
-  switch (action_enum) {
-    case ax::mojom::Action::kDoDefault:
-      fuchsia_actions.push_back(
-          fuchsia::accessibility::semantics::Action::DEFAULT);
-      break;
-    case ax::mojom::Action::kNone:
-    case ax::mojom::Action::kAnnotatePageImages:
-    case ax::mojom::Action::kBlur:
-    case ax::mojom::Action::kClearAccessibilityFocus:
-    case ax::mojom::Action::kCustomAction:
-    case ax::mojom::Action::kDecrement:
-    case ax::mojom::Action::kFocus:
-    case ax::mojom::Action::kGetImageData:
-    case ax::mojom::Action::kGetTextLocation:
-    case ax::mojom::Action::kHideTooltip:
-    case ax::mojom::Action::kHitTest:
-    case ax::mojom::Action::kIncrement:
-    case ax::mojom::Action::kInternalInvalidateTree:
-    case ax::mojom::Action::kLoadInlineTextBoxes:
-    case ax::mojom::Action::kReplaceSelectedText:
-    case ax::mojom::Action::kScrollBackward:
-    case ax::mojom::Action::kScrollDown:
-    case ax::mojom::Action::kScrollForward:
-    case ax::mojom::Action::kScrollLeft:
-    case ax::mojom::Action::kScrollRight:
-    case ax::mojom::Action::kScrollUp:
-    case ax::mojom::Action::kScrollToMakeVisible:
-    case ax::mojom::Action::kScrollToPoint:
-    case ax::mojom::Action::kSetAccessibilityFocus:
-    case ax::mojom::Action::kSetScrollOffset:
-    case ax::mojom::Action::kSetSelection:
-    case ax::mojom::Action::kSetSequentialFocusNavigationStartingPoint:
-    case ax::mojom::Action::kSetValue:
-    case ax::mojom::Action::kShowContextMenu:
-    case ax::mojom::Action::kSignalEndOfTest:
-    case ax::mojom::Action::kShowTooltip:
-      DVLOG(2) << "Action: " << action_enum;
-      break;
+  // Converts checked state of a node.
+  if (node.HasIntAttribute(ax::mojom::IntAttribute::kCheckedState)) {
+    ax::mojom::CheckedState ax_state = node.GetCheckedState();
+    switch (ax_state) {
+      case ax::mojom::CheckedState::kNone:
+        states.set_checked_state(
+            fuchsia::accessibility::semantics::CheckedState::NONE);
+        break;
+      case ax::mojom::CheckedState::kTrue:
+        states.set_checked_state(
+            fuchsia::accessibility::semantics::CheckedState::CHECKED);
+        break;
+      case ax::mojom::CheckedState::kFalse:
+        states.set_checked_state(
+            fuchsia::accessibility::semantics::CheckedState::UNCHECKED);
+        break;
+      case ax::mojom::CheckedState::kMixed:
+        states.set_checked_state(
+            fuchsia::accessibility::semantics::CheckedState::MIXED);
+        break;
+    }
+  }
+
+  // Indicates whether a node has been selected.
+  if (node.HasBoolAttribute(ax::mojom::BoolAttribute::kSelected)) {
+    states.set_selected(
+        node.GetBoolAttribute(ax::mojom::BoolAttribute::kSelected));
+  }
+
+  // Indicates if the node is hidden.
+  states.set_hidden(node.HasState(ax::mojom::State::kInvisible));
+
+  // The user entered value of the node, if applicable.
+  if (node.HasStringAttribute(ax::mojom::StringAttribute::kValue)) {
+    const std::string& value =
+        node.GetStringAttribute(ax::mojom::StringAttribute::kValue);
+    states.set_value(value.substr(0, MAX_LABEL_SIZE));
+  }
+
+  return states;
+}
+
+std::vector<fuchsia::accessibility::semantics::Action> ConvertActions(
+    const ui::AXNodeData& node) {
+  std::vector<fuchsia::accessibility::semantics::Action> fuchsia_actions;
+
+  if (node.HasAction(ax::mojom::Action::kDoDefault)) {
+    fuchsia_actions.push_back(
+        fuchsia::accessibility::semantics::Action::DEFAULT);
+  }
+  if (node.HasAction(ax::mojom::Action::kFocus)) {
+    fuchsia_actions.push_back(
+        fuchsia::accessibility::semantics::Action::SET_FOCUS);
+  }
+  if (node.HasAction(ax::mojom::Action::kSetValue)) {
+    fuchsia_actions.push_back(
+        fuchsia::accessibility::semantics::Action::SET_VALUE);
+  }
+  if (node.HasAction(ax::mojom::Action::kScrollToMakeVisible)) {
+    fuchsia_actions.push_back(
+        fuchsia::accessibility::semantics::Action::SHOW_ON_SCREEN);
   }
 
   return fuchsia_actions;
@@ -116,12 +159,9 @@
   fuchsia::accessibility::semantics::Node fuchsia_node;
   fuchsia_node.set_node_id(bit_cast<uint32_t>(node.id));
   fuchsia_node.set_role(ConvertRole(node.role));
-  // TODO(fxb/18796): Handle node state conversions once available.
-  if (node.HasStringAttribute(ax::mojom::StringAttribute::kName)) {
-    fuchsia_node.set_attributes(SetAttributes(
-        node.GetStringAttribute(ax::mojom::StringAttribute::kName)));
-  }
-  fuchsia_node.set_actions(ConvertActions(node.actions));
+  fuchsia_node.set_states(ConvertStates(node));
+  fuchsia_node.set_attributes(ConvertAttributes(node));
+  fuchsia_node.set_actions(ConvertActions(node));
   fuchsia_node.set_child_ids(ConvertChildIds(node.child_ids));
   fuchsia_node.set_location(ConvertBoundingBox(node.relative_bounds.bounds));
   if (node.relative_bounds.transform) {
diff --git a/fuchsia/engine/browser/ax_tree_converter_unittest.cc b/fuchsia/engine/browser/ax_tree_converter_unittest.cc
index 3dc1ad72..16bdfba 100644
--- a/fuchsia/engine/browser/ax_tree_converter_unittest.cc
+++ b/fuchsia/engine/browser/ax_tree_converter_unittest.cc
@@ -12,13 +12,17 @@
 
 using fuchsia::accessibility::semantics::Action;
 using fuchsia::accessibility::semantics::Attributes;
+using fuchsia::accessibility::semantics::CheckedState;
 using fuchsia::accessibility::semantics::Node;
 using fuchsia::accessibility::semantics::Role;
+using fuchsia::accessibility::semantics::States;
 
 namespace {
 
 const char kLabel1[] = "label nodes, not people";
 const char kLabel2[] = "fancy stickers";
+const char kDescription1[] = "this node does some stuff";
+const char kValue1[] = "user entered value";
 const int32_t kChildId1 = 23901;
 const int32_t kChildId2 = 484345;
 const int32_t kChildId3 = 4156877;
@@ -29,64 +33,33 @@
 const std::array<float, 16> k4DIdentityMatrix = {1, 0, 0, 0, 0, 1, 0, 0,
                                                  0, 0, 1, 0, 0, 0, 0, 1};
 
-bool SemanticNodesAreEqual(const Node& first, const Node& second) {
-  if (first.node_id() != second.node_id())
-    return false;
-  if (first.has_role() && second.has_role() && first.role() != second.role()) {
-    return false;
-  }
-  if (first.has_attributes() && second.has_attributes() &&
-      first.attributes().label() != second.attributes().label()) {
-    return false;
-  }
-  if (first.has_actions() && second.has_actions() &&
-      first.actions() != second.actions()) {
-    return false;
-  }
-  if (first.has_child_ids() && second.has_child_ids() &&
-      first.child_ids() != second.child_ids()) {
-    return false;
-  }
-  if (first.has_location() && second.has_location()) {
-    if (first.location().min.x != second.location().min.x)
-      return false;
-    if (first.location().min.y != second.location().min.y)
-      return false;
-    if (first.location().min.z != second.location().min.z)
-      return false;
-    if (first.location().max.x != second.location().max.x)
-      return false;
-    if (first.location().max.y != second.location().max.y)
-      return false;
-    if (first.location().max.z != second.location().max.z)
-      return false;
-  }
-  if (first.has_transform() && second.has_transform() &&
-      first.transform().matrix != second.transform().matrix) {
-    return false;
-  }
-
-  return true;
-}
-
 ui::AXNodeData CreateAXNodeData(ax::mojom::Role role,
-                                uint32_t actions,
+                                ax::mojom::Action action,
                                 std::vector<int32_t> child_ids,
                                 ui::AXRelativeBounds relative_bounds,
-                                base::StringPiece name) {
+                                base::StringPiece name,
+                                base::StringPiece description,
+                                ax::mojom::CheckedState checked_state) {
   ui::AXNodeData node;
   node.role = role;
-  node.actions = actions;
+  node.AddAction(action);
+  node.AddIntAttribute(ax::mojom::IntAttribute::kCheckedState,
+                       static_cast<int32_t>(checked_state));
   node.child_ids = child_ids;
   node.relative_bounds = relative_bounds;
   if (!name.empty())
     node.AddStringAttribute(ax::mojom::StringAttribute::kName, name.data());
+  if (!description.empty()) {
+    node.AddStringAttribute(ax::mojom::StringAttribute::kDescription,
+                            description.data());
+  }
   return node;
 }
 
 Node CreateSemanticNode(uint32_t id,
                         Role role,
                         Attributes attributes,
+                        States states,
                         std::vector<Action> actions,
                         std::vector<uint32_t> child_ids,
                         fuchsia::ui::gfx::BoundingBox location,
@@ -95,6 +68,7 @@
   node.set_node_id(id);
   node.set_role(role);
   node.set_attributes(std::move(attributes));
+  node.set_states(std::move(states));
   node.set_actions(actions);
   node.set_child_ids(child_ids);
   node.set_location(location);
@@ -116,47 +90,64 @@
   relative_bounds.transform =
       std::make_unique<gfx::Transform>(gfx::Transform::kSkipInitialization);
   relative_bounds.transform->MakeIdentity();
-  auto source_node_data =
-      CreateAXNodeData(ax::mojom::Role::kButton,
-                       static_cast<uint32_t>(ax::mojom::Action::kDoDefault),
-                       std::vector<int32_t>{kChildId1, kChildId2, kChildId3},
-                       relative_bounds, kLabel1);
+  auto source_node_data = CreateAXNodeData(
+      ax::mojom::Role::kButton, ax::mojom::Action::kFocus,
+      std::vector<int32_t>{kChildId1, kChildId2, kChildId3}, relative_bounds,
+      kLabel1, kDescription1, ax::mojom::CheckedState::kMixed);
+  source_node_data.AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, false);
+  source_node_data.RemoveState(ax::mojom::State::kInvisible);
   auto converted_node = AXNodeDataToSemanticNode(source_node_data);
   EXPECT_EQ(static_cast<uint32_t>(source_node_data.id),
             converted_node.node_id());
 
   Attributes attributes;
   attributes.set_label(kLabel1);
+  attributes.set_secondary_label(kDescription1);
   fuchsia::ui::gfx::BoundingBox box;
   box.min = scenic::NewVector3({kRectX, kRectY + kRectHeight, 0.0f});
   box.max = scenic::NewVector3({kRectHeight, kRectY, 0.0f});
   fuchsia::ui::gfx::Matrix4Value mat =
       scenic::NewMatrix4Value(k4DIdentityMatrix);
+  States states;
+  states.set_checked_state(CheckedState::MIXED);
+  states.set_hidden(false);
+  states.set_selected(false);
   auto expected_node = CreateSemanticNode(
-      source_node_data.id, Role::UNKNOWN, std::move(attributes),
-      std::vector<Action>{Action::DEFAULT},
+      source_node_data.id, Role::BUTTON, std::move(attributes),
+      std::move(states), std::vector<Action>{Action::SET_FOCUS},
       std::vector<uint32_t>{kChildId1, kChildId2, kChildId3}, box, mat.value);
 
-  EXPECT_TRUE(SemanticNodesAreEqual(std::move(converted_node),
-                                    std::move(expected_node)));
+  EXPECT_TRUE(fidl::Equals(converted_node, expected_node));
 }
 
 TEST_F(AXTreeConverterTest, SomeFieldsSetAndEqual) {
   ui::AXNodeData source_node_data;
-  source_node_data.actions =
-      static_cast<uint32_t>(ax::mojom::Action::kDoDefault);
+  source_node_data.AddAction(ax::mojom::Action::kFocus);
+  source_node_data.AddAction(ax::mojom::Action::kSetValue);
   source_node_data.child_ids = std::vector<int32_t>{kChildId1};
+  source_node_data.role = ax::mojom::Role::kImage;
+  source_node_data.AddStringAttribute(ax::mojom::StringAttribute::kValue,
+                                      kValue1);
   auto converted_node = AXNodeDataToSemanticNode(source_node_data);
   EXPECT_EQ(static_cast<uint32_t>(source_node_data.id),
             converted_node.node_id());
 
   Node expected_node;
   expected_node.set_node_id(source_node_data.id);
-  expected_node.set_actions(std::vector<Action>{Action::DEFAULT});
+  expected_node.set_actions(
+      std::vector<Action>{Action::SET_FOCUS, Action::SET_VALUE});
   expected_node.set_child_ids(std::vector<uint32_t>{kChildId1});
+  expected_node.set_role(Role::IMAGE);
+  States states;
+  states.set_hidden(false);
+  states.set_value(kValue1);
+  expected_node.set_states(std::move(states));
+  Attributes attributes;
+  expected_node.set_attributes(std::move(attributes));
+  fuchsia::ui::gfx::BoundingBox box;
+  expected_node.set_location(std::move(box));
 
-  EXPECT_TRUE(SemanticNodesAreEqual(std::move(converted_node),
-                                    std::move(expected_node)));
+  EXPECT_TRUE(fidl::Equals(converted_node, expected_node));
 }
 
 TEST_F(AXTreeConverterTest, FieldMismatch) {
@@ -165,31 +156,32 @@
   relative_bounds.transform =
       std::make_unique<gfx::Transform>(gfx::Transform::kSkipInitialization);
   relative_bounds.transform->MakeIdentity();
-  auto source_node_data =
-      CreateAXNodeData(ax::mojom::Role::kButton,
-                       static_cast<uint32_t>(ax::mojom::Action::kDoDefault),
-                       std::vector<int32_t>{kChildId1, kChildId2, kChildId3},
-                       relative_bounds, kLabel1);
+  auto source_node_data = CreateAXNodeData(
+      ax::mojom::Role::kHeader, ax::mojom::Action::kSetValue,
+      std::vector<int32_t>{kChildId1, kChildId2, kChildId3}, relative_bounds,
+      kLabel1, kDescription1, ax::mojom::CheckedState::kFalse);
   auto converted_node = AXNodeDataToSemanticNode(source_node_data);
   EXPECT_EQ(static_cast<uint32_t>(source_node_data.id),
             converted_node.node_id());
 
   Attributes attributes;
   attributes.set_label(kLabel1);
+  attributes.set_secondary_label(kDescription1);
+  States states;
+  states.set_hidden(false);
+  states.set_checked_state(CheckedState::UNCHECKED);
   fuchsia::ui::gfx::BoundingBox box;
-  std::array<float, 3> min = {kRectX, kRectY + kRectHeight, 0.0f};
-  std::array<float, 3> max = {kRectHeight, kRectY, 0.0f};
-  box.min = scenic::NewVector3(min);
-  box.max = scenic::NewVector3(max);
+  box.min = scenic::NewVector3({kRectX, kRectY + kRectHeight, 0.0f});
+  box.max = scenic::NewVector3({kRectHeight, kRectY, 0.0f});
   fuchsia::ui::gfx::Matrix4Value mat =
       scenic::NewMatrix4Value(k4DIdentityMatrix);
   auto expected_node = CreateSemanticNode(
-      source_node_data.id, Role::UNKNOWN, std::move(attributes),
-      std::vector<Action>{Action::DEFAULT},
+      source_node_data.id, Role::HEADER, std::move(attributes),
+      std::move(states), std::vector<Action>{Action::SET_VALUE},
       std::vector<uint32_t>{kChildId1, kChildId2, kChildId3}, box, mat.value);
 
   // Start with nodes being equal.
-  EXPECT_TRUE(SemanticNodesAreEqual(converted_node, expected_node));
+  EXPECT_TRUE(fidl::Equals(converted_node, expected_node));
 
   // Make a copy of |source_node_data| and change the name attribute. Check that
   // the resulting |converted_node| is different from |expected_node|.
@@ -197,13 +189,13 @@
   modified_node_data.AddStringAttribute(ax::mojom::StringAttribute::kName,
                                         kLabel2);
   converted_node = AXNodeDataToSemanticNode(modified_node_data);
-  EXPECT_FALSE(SemanticNodesAreEqual(converted_node, expected_node));
+  EXPECT_FALSE(fidl::Equals(converted_node, expected_node));
 
   // The same as above, this time changing |child_ids|.
   modified_node_data = source_node_data;
   modified_node_data.child_ids = std::vector<int32_t>{};
   converted_node = AXNodeDataToSemanticNode(modified_node_data);
-  EXPECT_FALSE(SemanticNodesAreEqual(converted_node, expected_node));
+  EXPECT_FALSE(fidl::Equals(converted_node, expected_node));
 }
 
 }  // namespace
diff --git a/headless/test/data/protocol/emulation/virtual-time-cancel-client-redirect.js b/headless/test/data/protocol/emulation/virtual-time-cancel-client-redirect.js
index 0df0ab8..9bb160d 100644
--- a/headless/test/data/protocol/emulation/virtual-time-cancel-client-redirect.js
+++ b/headless/test/data/protocol/emulation/virtual-time-cancel-client-redirect.js
@@ -45,10 +45,14 @@
   let frameTimeTicks = 0;
   dp.Emulation.onVirtualTimeBudgetExpired(async e => {
     frameTimeTicks += virtualTimeChunkSize;
-    await dp.HeadlessExperimental.beginFrame({
-        frameTimeTicks: virtualTimeTicksBase + frameTimeTicks,
-        interval: virtualTimeChunkSize,
-        noDisplayUpdates: false});
+    const frameArgs = {
+      frameTimeTicks: virtualTimeTicksBase + frameTimeTicks,
+      interval: virtualTimeChunkSize,
+      noDisplayUpdates: false
+    };
+    if (frameTimeTicks > 500)
+      frameArgs.screenshot = {format: 'png', quality: 100};
+    await dp.HeadlessExperimental.beginFrame(frameArgs);
     await dp.Emulation.setVirtualTimePolicy({
         policy: 'pauseIfNetworkFetchesPending', budget: virtualTimeChunkSize});
   });
diff --git a/infra/config/buckets/try.star b/infra/config/buckets/try.star
index ef32e46..a69dd66 100644
--- a/infra/config/buckets/try.star
+++ b/infra/config/buckets/try.star
@@ -1546,7 +1546,8 @@
 win_builder(
     name = 'win10_chromium_x64_coverage_rel_ng',
     os = os.WINDOWS_10,
-    use_clang_coverage = True
+    use_clang_coverage = True,
+    tryjob = tryjob(experiment_percentage = 3),
 )
 
 win_builder(
diff --git a/infra/config/generated/commit-queue.cfg b/infra/config/generated/commit-queue.cfg
index 27100cdd..61dc987 100644
--- a/infra/config/generated/commit-queue.cfg
+++ b/infra/config/generated/commit-queue.cfg
@@ -1041,7 +1041,7 @@
       >
       builders: <
         name: "chromium/try/win10_chromium_x64_coverage_rel_ng"
-        includable_only: true
+        experiment_percentage: 3
       >
       builders: <
         name: "chromium/try/win10_chromium_x64_dbg_ng"
diff --git a/infra/config/generated/cq-builders.md b/infra/config/generated/cq-builders.md
index 612daba..01bfded 100644
--- a/infra/config/generated/cq-builders.md
+++ b/infra/config/generated/cq-builders.md
@@ -320,3 +320,6 @@
 * [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
 
+* [win10_chromium_x64_coverage_rel_ng](https://ci.chromium.org/p/chromium/builders/try/win10_chromium_x64_coverage_rel_ng) ([definition](https://cs.chromium.org/search?q=package:%5Echromium$+file:/cq.star$+-file:/beta/+-file:/stable/+win10_chromium_x64_coverage_rel_ng)) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+win10_chromium_x64_coverage_rel_ng))
+  * Experiment percentage: 3
+
diff --git a/ios/build/bots/scripts/run.py b/ios/build/bots/scripts/run.py
index a3cf9a9..796df22 100755
--- a/ios/build/bots/scripts/run.py
+++ b/ios/build/bots/scripts/run.py
@@ -29,301 +29,345 @@
 import xcodebuild_runner
 
 
-def main():
-  logging.basicConfig(format='[%(asctime)s:%(levelname)s] %(message)s',
-    level=logging.DEBUG, datefmt='%I:%M:%S')
+class Runner():
+  """
+  Object to encapsulate iOS test runner execution coordination. Parses
+  arguments and invokes underlying test runners accordingly.
+  """
+
+  def __init__(self, args=None):
+    """
+    args = argparse Namespace object.
+    test_args = string list of args.
+    """
+    self.args = argparse.Namespace()
+    self.test_args = []
+
+    if args:
+      self.parse_args(args)
+
+  def run(self, args):
+    """
+    Main coordinating function.
+    """
+    self.parse_args(args)
+
+    summary = {}
+    tr = None
+
+    if not os.path.exists(self.args.out_dir):
+      os.makedirs(self.args.out_dir)
+
+    try:
+      if self.args.xcode_parallelization:
+        tr = xcodebuild_runner.SimulatorParallelTestRunner(
+            self.args.app,
+            self.args.host_app,
+            self.args.iossim,
+            self.args.xcode_build_version,
+            self.args.version,
+            self.args.platform,
+            out_dir=self.args.out_dir,
+            mac_toolchain=self.args.mac_toolchain_cmd,
+            retries=self.args.retries,
+            shards=self.args.shards,
+            xcode_path=self.args.xcode_path,
+            test_cases=self.args.test_cases,
+            test_args=self.test_args,
+            env_vars=self.args.env_var)
+      elif self.args.replay_path != 'NO_PATH':
+        tr = wpr_runner.WprProxySimulatorTestRunner(
+            self.args.app,
+            self.args.host_app,
+            self.args.iossim,
+            self.args.replay_path,
+            self.args.platform,
+            self.args.version,
+            self.args.wpr_tools_path,
+            self.args.xcode_build_version,
+            self.args.out_dir,
+            env_vars=self.args.env_var,
+            mac_toolchain=self.args.mac_toolchain_cmd,
+            retries=self.args.retries,
+            shards=self.args.shards,
+            test_args=self.test_args,
+            test_cases=self.args.test_cases,
+            xcode_path=self.args.xcode_path,
+            xctest=self.args.xctest,
+        )
+      elif self.args.iossim and self.args.platform and self.args.version:
+        tr = test_runner.SimulatorTestRunner(
+            self.args.app,
+            self.args.iossim,
+            self.args.platform,
+            self.args.version,
+            self.args.xcode_build_version,
+            self.args.out_dir,
+            env_vars=self.args.env_var,
+            mac_toolchain=self.args.mac_toolchain_cmd,
+            retries=self.args.retries,
+            shards=self.args.shards,
+            test_args=self.test_args,
+            test_cases=self.args.test_cases,
+            wpr_tools_path=self.args.wpr_tools_path,
+            xcode_path=self.args.xcode_path,
+            xctest=self.args.xctest,
+        )
+      elif self.args.xcodebuild_device_runner and self.args.xctest:
+        tr = xcodebuild_runner.DeviceXcodeTestRunner(
+            app_path=self.args.app,
+            host_app_path=self.args.host_app,
+            xcode_build_version=self.args.xcode_build_version,
+            out_dir=self.args.out_dir,
+            mac_toolchain=self.args.mac_toolchain_cmd,
+            retries=self.args.retries,
+            xcode_path=self.args.xcode_path,
+            test_cases=self.args.test_cases,
+            test_args=self.test_args,
+            env_vars=self.args.env_var)
+      else:
+        tr = test_runner.DeviceTestRunner(
+            self.args.app,
+            self.args.xcode_build_version,
+            self.args.out_dir,
+            env_vars=self.args.env_var,
+            mac_toolchain=self.args.mac_toolchain_cmd,
+            restart=self.args.restart,
+            retries=self.args.retries,
+            test_args=self.test_args,
+            test_cases=self.args.test_cases,
+            xcode_path=self.args.xcode_path,
+            xctest=self.args.xctest,
+        )
+
+      return 0 if tr.launch() else 1
+    except test_runner.TestRunnerError as e:
+      sys.stderr.write(traceback.format_exc())
+      summary['step_text'] = '%s%s' % (e.__class__.__name__,
+                                       ': %s' % e.args[0] if e.args else '')
+
+      # test_runner.Launch returns 0 on success, 1 on failure, so return 2
+      # on exception to distinguish between a test failure, and a failure
+      # to launch the test at all.
+      return 2
+    finally:
+      if tr:
+        summary['logs'] = tr.logs
+
+      with open(os.path.join(self.args.out_dir, 'summary.json'), 'w') as f:
+        json.dump(summary, f)
+      if tr:
+        with open(os.path.join(self.args.out_dir, 'full_results.json'),
+                  'w') as f:
+          json.dump(tr.test_results, f)
+      test_runner.defaults_delete('com.apple.CoreSimulator',
+                                  'FramebufferServerRendererPolicy')
+
+  def parse_args(self, args):
+    """
+    Parse the args into args and test_args.
+    """
+    parser = argparse.ArgumentParser()
+
+    parser.add_argument(
+        '-x',
+        '--xcode-parallelization',
+        help='Run tests using xcodebuild\'s parallelization.',
+        action='store_true',
+    )
+    parser.add_argument(
+        '-a',
+        '--app',
+        help='Compiled .app to run for EG1, Compiled -Runner.app for EG2',
+        metavar='app',
+    )
+    parser.add_argument(
+        '-b',
+        '--xcode-build-version',
+        help='Xcode build version to install.',
+        required=True,
+        metavar='build_id',
+    )
+    parser.add_argument(
+        '-e',
+        '--env-var',
+        action='append',
+        help='Environment variable to pass to the test itself.',
+        metavar='ENV=val',
+    )
+    parser.add_argument(
+        '--host-app',
+        help='Compiled host .app to run.',
+        default='NO_PATH',
+        metavar='host_app',
+    )
+    parser.add_argument(
+        '-i',
+        '--iossim',
+        help='Compiled iossim to run the app on.',
+        metavar='iossim',
+    )
+    parser.add_argument(
+        '-j',
+        '--args-json',
+        default='{}',
+        help=
+        'Specify "env_var": [...] and "test_args": [...] using a JSON dict.',
+        metavar='{}',
+    )
+    parser.add_argument(
+        '--mac-toolchain-cmd',
+        help='Command to run mac_toolchain tool. Default: %(default)s.',
+        default='mac_toolchain',
+        metavar='mac_toolchain',
+    )
+    parser.add_argument(
+        '-o',
+        '--out-dir',
+        help='Directory to store all test data in.',
+        metavar='dir',
+        required=True,
+    )
+    parser.add_argument(
+        '-p',
+        '--platform',
+        help='Platform to simulate.',
+        metavar='sim',
+    )
+    parser.add_argument(
+        '--replay-path',
+        help=('Path to a directory containing WPR replay and recipe files, for '
+              'use with WprProxySimulatorTestRunner to replay a test suite '
+              'against multiple saved website interactions. '
+              'Default: %(default)s'),
+        default='NO_PATH',
+        metavar='replay-path',
+    )
+    parser.add_argument(
+        '--restart',
+        action='store_true',
+        help=argparse.SUPPRESS,
+    )
+    parser.add_argument(
+        '-r',
+        '--retries',
+        help='Number of times to retry failed test cases.',
+        metavar='n',
+        type=int,
+    )
+    parser.add_argument(
+        '-s',
+        '--shards',
+        help='Number of shards to split test cases.',
+        metavar='n',
+        type=int,
+    )
+    parser.add_argument(
+        '-t',
+        '--test-cases',
+        action='append',
+        help=('Tests that should be included in the test run. All other tests '
+              'will be excluded from this run. If unspecified, run all tests.'),
+        metavar='testcase',
+    )
+    parser.add_argument(
+        '--use-trusted-cert',
+        action='store_true',
+        help=('Whether to install a cert to the simulator to allow for local '
+              'HTTPS testing.'),
+    )
+    parser.add_argument(
+        '-v',
+        '--version',
+        help='Version of iOS the simulator should run.',
+        metavar='ver',
+    )
+    parser.add_argument(
+        '--wpr-tools-path',
+        help=(
+            'Location of WPR test tools (should be preinstalled, e.g. as part '
+            'of a swarming task requirement). Default: %(default)s.'),
+        default='NO_PATH',
+        metavar='wpr-tools-path',
+    )
+    parser.add_argument(
+        '--xcode-path',
+        metavar='PATH',
+        help=('Path to <Xcode>.app folder where contents of the app will be '
+              'installed. Default: %(default)s. WARNING: this folder will be '
+              'overwritten! This folder is intended to be a cached CIPD '
+              'installation.'),
+        default='Xcode.app',
+    )
+    parser.add_argument(
+        '--xcodebuild-device-runner',
+        help='Run tests using xcodebuild\'s on real device.',
+        action='store_true',
+        default=False,
+    )
+    parser.add_argument(
+        '--xctest',
+        action='store_true',
+        help='Whether or not the given app should be run as an XCTest.',
+    )
+
+    def load_from_json(args):
+      """
+      Load and set arguments from args_json
+      """
+      args_json = json.loads(args.args_json)
+      args.env_var = args.env_var or []
+      args.env_var.extend(args_json.get('env_var', []))
+      args.restart = args_json.get('restart', args.restart)
+      args.test_cases = args.test_cases or []
+      args.test_cases.extend(args_json.get('test_cases', []))
+      args.xctest = args_json.get('xctest', args.xctest)
+      args.xcode_parallelization = args_json.get('xcode_parallelization',
+                                                 args.xcode_parallelization)
+      args.xcodebuild_device_runner = (
+          args_json.get('xcodebuild_device_runner',
+                        args.xcodebuild_device_runner))
+      args.shards = args_json.get('shards', args.shards)
+      test_args.extend(args_json.get('test_args', []))
+
+    def validate(args):
+      """
+      Runs argument validation
+      """
+      if (not (args.xcode_parallelization or args.xcodebuild_device_runner) and
+          (args.iossim or args.platform or args.version)):
+        # If any of --iossim, --platform, or --version
+        # are specified then they must all be specified.
+        if not (args.iossim and args.platform and args.version):
+          parser.error('must specify all or none of '
+                       '-i/--iossim, -p/--platform, -v/--version')
+
+      if args.xcode_parallelization and not (args.platform and args.version):
+        parser.error('--xcode-parallelization also requires '
+                     'both -p/--platform and -v/--version')
+
+      if args.xcodebuild_device_runner and not (args.platform and args.version):
+        parser.error('--xcodebuild-device-runner also requires '
+                     'both -p/--platform and -v/--version')
+
+    args, test_args = parser.parse_known_args(args)
+    validate(args)
+    load_from_json(args)
+    self.args = args
+    self.test_args = test_args
+
+
+def main(args):
+  logging.basicConfig(
+      format='[%(asctime)s:%(levelname)s] %(message)s',
+      level=logging.DEBUG,
+      datefmt='%I:%M:%S')
 
   test_runner.defaults_delete('com.apple.CoreSimulator',
                               'FramebufferServerRendererPolicy')
-  args, test_args = parse_args()
-
-  summary = {}
-  tr = None
-
-  if not os.path.exists(args.out_dir):
-    os.makedirs(args.out_dir)
-
-  try:
-    if args.xcode_parallelization:
-      tr = xcodebuild_runner.SimulatorParallelTestRunner(
-          args.app,
-          args.host_app,
-          args.iossim,
-          args.xcode_build_version,
-          args.version,
-          args.platform,
-          out_dir=args.out_dir,
-          mac_toolchain=args.mac_toolchain_cmd,
-          retries=args.retries,
-          shards=args.shards,
-          xcode_path=args.xcode_path,
-          test_cases=args.test_cases,
-          test_args=test_args,
-          env_vars=args.env_var
-      )
-    elif args.replay_path != 'NO_PATH':
-      tr = wpr_runner.WprProxySimulatorTestRunner(
-          args.app,
-          args.host_app,
-          args.iossim,
-          args.replay_path,
-          args.platform,
-          args.version,
-          args.wpr_tools_path,
-          args.xcode_build_version,
-          args.out_dir,
-          env_vars=args.env_var,
-          mac_toolchain=args.mac_toolchain_cmd,
-          retries=args.retries,
-          shards=args.shards,
-          test_args=test_args,
-          test_cases=args.test_cases,
-          xcode_path=args.xcode_path,
-          xctest=args.xctest,
-      )
-    elif args.iossim and args.platform and args.version:
-      tr = test_runner.SimulatorTestRunner(
-          args.app,
-          args.iossim,
-          args.platform,
-          args.version,
-          args.xcode_build_version,
-          args.out_dir,
-          env_vars=args.env_var,
-          mac_toolchain=args.mac_toolchain_cmd,
-          retries=args.retries,
-          shards=args.shards,
-          test_args=test_args,
-          test_cases=args.test_cases,
-          wpr_tools_path=args.wpr_tools_path,
-          xcode_path=args.xcode_path,
-          xctest=args.xctest,
-      )
-    elif args.xcodebuild_device_runner and args.xctest:
-      tr = xcodebuild_runner.DeviceXcodeTestRunner(
-          app_path=args.app,
-          host_app_path=args.host_app,
-          xcode_build_version=args.xcode_build_version,
-          out_dir=args.out_dir,
-          mac_toolchain=args.mac_toolchain_cmd,
-          retries=args.retries,
-          xcode_path=args.xcode_path,
-          test_cases=args.test_cases,
-          test_args=test_args,
-          env_vars=args.env_var)
-    else:
-      tr = test_runner.DeviceTestRunner(
-          args.app,
-          args.xcode_build_version,
-          args.out_dir,
-          env_vars=args.env_var,
-          mac_toolchain=args.mac_toolchain_cmd,
-          restart=args.restart,
-          retries=args.retries,
-          test_args=test_args,
-          test_cases=args.test_cases,
-          xcode_path=args.xcode_path,
-          xctest=args.xctest,
-      )
-
-    return 0 if tr.launch() else 1
-  except test_runner.TestRunnerError as e:
-    sys.stderr.write(traceback.format_exc())
-    summary['step_text'] = '%s%s' % (
-      e.__class__.__name__, ': %s' % e.args[0] if e.args else '')
-
-    # test_runner.Launch returns 0 on success, 1 on failure, so return 2
-    # on exception to distinguish between a test failure, and a failure
-    # to launch the test at all.
-    return 2
-  finally:
-    if tr:
-      summary['logs'] = tr.logs
-
-    with open(os.path.join(args.out_dir, 'summary.json'), 'w') as f:
-      json.dump(summary, f)
-    if tr:
-      with open(os.path.join(args.out_dir, 'full_results.json'), 'w') as f:
-        json.dump(tr.test_results, f)
-    test_runner.defaults_delete('com.apple.CoreSimulator',
-                                'FramebufferServerRendererPolicy')
-
-
-def parse_args():
-  parser = argparse.ArgumentParser()
-
-  parser.add_argument(
-      '-x',
-      '--xcode-parallelization',
-      help='Run tests using xcodebuild\'s parallelization.',
-      action='store_true',
-  )
-  parser.add_argument(
-    '-a',
-    '--app',
-    help='Compiled .app to run for EG1, Compiled -Runner.app for EG2',
-    metavar='app',
-  )
-  parser.add_argument(
-    '-b',
-    '--xcode-build-version',
-    help='Xcode build version to install.',
-    required=True,
-    metavar='build_id',
-  )
-  parser.add_argument(
-    '-e',
-    '--env-var',
-    action='append',
-    help='Environment variable to pass to the test itself.',
-    metavar='ENV=val',
-  )
-  parser.add_argument(
-    '--host-app',
-    help='Compiled host .app to run.',
-    default='NO_PATH',
-    metavar='host_app',
-  )
-  parser.add_argument(
-    '-i',
-    '--iossim',
-    help='Compiled iossim to run the app on.',
-    metavar='iossim',
-  )
-  parser.add_argument(
-    '-j',
-    '--args-json',
-    default='{}',
-    help='Specify "env_var": [...] and "test_args": [...] using a JSON dict.',
-    metavar='{}',
-  )
-  parser.add_argument(
-    '--mac-toolchain-cmd',
-    help='Command to run mac_toolchain tool. Default: %(default)s.',
-    default='mac_toolchain',
-    metavar='mac_toolchain',
-  )
-  parser.add_argument(
-    '-o',
-    '--out-dir',
-    help='Directory to store all test data in.',
-    metavar='dir',
-    required=True,
-  )
-  parser.add_argument(
-    '-p',
-    '--platform',
-    help='Platform to simulate.',
-    metavar='sim',
-  )
-  parser.add_argument(
-    '--replay-path',
-    help=('Path to a directory containing WPR replay and recipe files, for '
-          'use with WprProxySimulatorTestRunner to replay a test suite'
-          ' against multiple saved website interactions. Default: %(default)s'),
-    default='NO_PATH',
-    metavar='replay-path',
-  )
-  parser.add_argument(
-    '--restart',
-    action='store_true',
-    help=argparse.SUPPRESS,
-  )
-  parser.add_argument(
-    '-r',
-    '--retries',
-    help='Number of times to retry failed test cases.',
-    metavar='n',
-    type=int,
-  )
-  parser.add_argument(
-    '-s',
-    '--shards',
-    help='Number of shards to split test cases.',
-    metavar='n',
-    type=int,
-  )
-  parser.add_argument(
-    '-t',
-    '--test-cases',
-    action='append',
-    help=('Tests that should be included in the test run. All other tests '
-          'will be excluded from this run. If unspecified, run all tests.'),
-    metavar='testcase',
-  )
-  parser.add_argument(
-    '--use-trusted-cert',
-    action='store_true',
-    help=('Whether to install a cert to the simulator to allow for local HTTPS'
-         'testing.'),
-  )
-  parser.add_argument(
-    '-v',
-    '--version',
-    help='Version of iOS the simulator should run.',
-    metavar='ver',
-  )
-  parser.add_argument(
-    '--wpr-tools-path',
-    help=('Location of WPR test tools (should be preinstalled, e.g. as part of '
-         'a swarming task requirement). Default: %(default)s.'),
-    default='NO_PATH',
-    metavar='wpr-tools-path',
-  )
-  parser.add_argument(
-    '--xcode-path',
-    metavar='PATH',
-    help=('Path to <Xcode>.app folder where contents of the app will be '
-          'installed. Default: %(default)s. WARNING: this folder will be '
-          'overwritten! This folder is intended to be a cached CIPD '
-          'installation.'),
-    default='Xcode.app',
-  )
-  parser.add_argument(
-    '--xcodebuild-device-runner',
-    help='Run tests using xcodebuild\'s on real device.',
-    action='store_true',
-    default=False,
-  )
-  parser.add_argument(
-    '--xctest',
-    action='store_true',
-    help='Whether or not the given app should be run as an XCTest.',
-  )
-
-  args, test_args = parser.parse_known_args()
-  if not (args.xcode_parallelization or args.xcodebuild_device_runner) and (
-      args.iossim or args.platform or args.version):
-    # If any of --iossim, --platform, or --version
-    # are specified then they must all be specified.
-    if not (args.iossim and args.platform and args.version):
-      parser.error(
-        'must specify all or none of -i/--iossim, -p/--platform, -v/--version')
-
-  if args.xcode_parallelization and not (args.platform and args.version):
-    parser.error(''.join(['--xcode-parallezation also requires',
-                          'both -p/--platform and -v/--version']))
-
-  if args.xcodebuild_device_runner and not (args.platform and args.version):
-    parser.error(''.join(['--xcodebuild-device-runner also requires',
-                          'both -p/--platform and -v/--version']))
-
-  args_json = json.loads(args.args_json)
-  args.env_var = args.env_var or []
-  args.env_var.extend(args_json.get('env_var', []))
-  args.restart = args_json.get('restart', args.restart)
-  args.test_cases = args.test_cases or []
-  args.test_cases.extend(args_json.get('test_cases', []))
-  args.xctest = args_json.get('xctest', args.xctest)
-  args.xcode_parallelization = args_json.get('xcode_parallelization',
-                                             args.xcode_parallelization)
-  args.xcodebuild_device_runner = args_json.get('xcodebuild_device_runner',
-                                                args.xcodebuild_device_runner)
-  args.shards = args_json.get('shards', args.shards)
-  test_args.extend(args_json.get('test_args', []))
-
-  return args, test_args
+  runner = Runner()
+  return runner.run(args)
 
 
 if __name__ == '__main__':
-  sys.exit(main())
+  sys.exit(main(sys.argv[1:]))
diff --git a/ios/build/bots/scripts/run_test.py b/ios/build/bots/scripts/run_test.py
new file mode 100755
index 0000000..a4cff30
--- /dev/null
+++ b/ios/build/bots/scripts/run_test.py
@@ -0,0 +1,225 @@
+#!/usr/bin/python
+# 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.
+"""Unittests for run.py."""
+
+import json
+import re
+import unittest
+
+import run
+
+
+class UnitTest(unittest.TestCase):
+
+  def test_parse_args_ok(self):
+    cmd = [
+        '--app',
+        './foo-Runner.app',
+        '--host-app',
+        './bar.app',
+
+        # Required
+        '--xcode-build-version',
+        '123abc',
+        '--out-dir',
+        'some/dir'
+    ]
+
+    runner = run.Runner()
+    runner.parse_args(cmd)
+    self.assertTrue(runner.args.app == './foo-Runner.app')
+
+  def test_parse_args_iossim_platform_version(self):
+    """
+    iossim, platforma and version should all be set.
+    missing iossim
+    """
+    test_cases = [
+        {
+            'error':
+                2,
+            'cmd': [
+                '--platform',
+                'iPhone X',
+                '--version',
+                '13.2.2',
+
+                # Required
+                '--xcode-build-version',
+                '123abc',
+                '--out-dir',
+                'some/dir'
+            ],
+        },
+        {
+            'error':
+                2,
+            'cmd': [
+                '--iossim',
+                'path/to/iossim',
+                '--version',
+                '13.2.2',
+
+                # Required
+                '--xcode-build-version',
+                '123abc',
+                '--out-dir',
+                'some/dir'
+            ],
+        },
+        {
+            'error':
+                2,
+            'cmd': [
+                '--iossim',
+                'path/to/iossim',
+                '--platform',
+                'iPhone X',
+
+                # Required
+                '--xcode-build-version',
+                '123abc',
+                '--out-dir',
+                'some/dir'
+            ],
+        },
+    ]
+
+    runner = run.Runner()
+    for test_case in test_cases:
+      with self.assertRaises(SystemExit) as ctx:
+        runner.parse_args(test_case['cmd'])
+        self.assertTrue(re.match('must specify all or none of *', ctx.message))
+        self.assertEqual(ctx.exception.code, test_case['error'])
+
+  def test_parse_args_xcode_parallelization_requirements(self):
+    """
+    xcode parallelization set requires both platform and version
+    """
+    test_cases = [
+        {
+            'error':
+                2,
+            'cmd': [
+                '--xcode-parallelization',
+                '--platform',
+                'iPhone X',
+
+                # Required
+                '--xcode-build-version',
+                '123abc',
+                '--out-dir',
+                'some/dir'
+            ]
+        },
+        {
+            'error':
+                2,
+            'cmd': [
+                '--xcode-parallelization',
+                '--version',
+                '13.2.2',
+
+                # Required
+                '--xcode-build-version',
+                '123abc',
+                '--out-dir',
+                'some/dir'
+            ]
+        }
+    ]
+
+    runner = run.Runner()
+    for test_case in test_cases:
+      with self.assertRaises(SystemExit) as ctx:
+        runner.parse_args(test_case['cmd'])
+        self.assertTrue(
+            re.match('--xcode-parallelization also requires both *',
+                     ctx.message))
+        self.assertEqual(ctx.exception.code, test_case['error'])
+
+  def test_parse_args_xcodebuild_device_runner_requirements(self):
+    """
+    xcodebuild_device_runner requires both platform and version
+    """
+    test_cases = [
+        {
+            'error':
+                2,
+            'cmd': [
+                '--xcodebuild-device-runner',
+                '--platform',
+                'iPhone X',
+
+                # Required
+                '--xcode-build-version',
+                '123abc',
+                '--out-dir',
+                'some/dir'
+            ]
+        },
+        {
+            'error':
+                2,
+            'cmd': [
+                '--xcodebuild-device-runner',
+                '--version',
+                '13.2.2',
+
+                # Required
+                '--xcode-build-version',
+                '123abc',
+                '--out-dir',
+                'some/dir'
+            ]
+        }
+    ]
+
+    runner = run.Runner()
+    for test_case in test_cases:
+      with self.assertRaises(SystemExit) as ctx:
+        runner.parse_args(test_case['cmd'])
+        self.assertTrue(
+            re.match('--xcodebuild-device-runner also requires '
+                     'both *', ctx.message))
+        self.assertEqual(ctx.exception.code, test_case['error'])
+
+  def test_parse_args_from_json(self):
+    json_args = {
+        'test_cases': ['test1'],
+        'restart': 'true',
+        'xcode_parallelization': True,
+        'shards': 2
+    }
+
+    cmd = [
+        '--shards',
+        '1',
+        '--platform',
+        'iPhone X',
+        '--version',
+        '13.2.2',
+        '--args-json',
+        json.dumps(json_args),
+
+        # Required
+        '--xcode-build-version',
+        '123abc',
+        '--out-dir',
+        'some/dir'
+    ]
+
+    # shards should be 2, since json arg takes precedence over cmd line
+    runner = run.Runner()
+    runner.parse_args(cmd)
+    # Empty array
+    self.assertEquals(len(runner.args.env_var), 0)
+    self.assertTrue(runner.args.xcode_parallelization)
+    self.assertTrue(runner.args.restart)
+    self.assertEquals(runner.args.shards, 2)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/ios/build/bots/tests/eg2_tests.json b/ios/build/bots/tests/eg2_tests.json
index cdccf68..9a3e4690 100644
--- a/ios/build/bots/tests/eg2_tests.json
+++ b/ios/build/bots/tests/eg2_tests.json
@@ -22,7 +22,8 @@
         {
             "app": "ios_chrome_ui_eg2tests_module",
             "host": "ios_chrome_eg2tests",
-            "shards": 2
+            "shards": 2,
+            "shard size": 20
         },
         {
             "app": "ios_chrome_web_eg2tests_module",
diff --git a/ios/chrome/app/resources/BUILD.gn b/ios/chrome/app/resources/BUILD.gn
index dce25f7..dddf70f 100644
--- a/ios/chrome/app/resources/BUILD.gn
+++ b/ios/chrome/app/resources/BUILD.gn
@@ -61,6 +61,7 @@
   visibility = [ ":packed_resources" ]
   sources = [
     "$root_gen_dir/components/components_resources.pak",
+    "$root_gen_dir/components/dev_ui_components_resources.pak",
     "$root_gen_dir/components/sync_driver_resources.pak",
     "$root_gen_dir/ios/chrome/ios_resources.pak",
     "$root_gen_dir/ios/web/ios_web_resources.pak",
diff --git a/ios/chrome/browser/overlays/BUILD.gn b/ios/chrome/browser/overlays/BUILD.gn
index e8e58d5..3b7839c 100644
--- a/ios/chrome/browser/overlays/BUILD.gn
+++ b/ios/chrome/browser/overlays/BUILD.gn
@@ -4,6 +4,7 @@
 
 source_set("overlays") {
   public = [
+    "public/overlay_browser_agent_base.h",
     "public/overlay_callback_manager.h",
     "public/overlay_dismissal_callback.h",
     "public/overlay_dispatch_callback.h",
@@ -28,6 +29,7 @@
   sources = [
     "default_overlay_request_cancel_handler.h",
     "default_overlay_request_cancel_handler.mm",
+    "overlay_browser_agent_base.mm",
     "overlay_callback_manager_impl.cc",
     "overlay_callback_manager_impl.h",
     "overlay_dispatch_callback.cc",
@@ -63,6 +65,7 @@
   testonly = true
   sources = [
     "default_overlay_request_cancel_handler_unittest.mm",
+    "overlay_browser_agent_base_unittest.mm",
     "overlay_callback_manager_impl_unittest.cc",
     "overlay_dispatch_callback_unittest.cc",
     "overlay_presenter_impl_unittest.mm",
diff --git a/ios/chrome/browser/overlays/overlay_browser_agent_base.mm b/ios/chrome/browser/overlays/overlay_browser_agent_base.mm
new file mode 100644
index 0000000..44cb1e3
--- /dev/null
+++ b/ios/chrome/browser/overlays/overlay_browser_agent_base.mm
@@ -0,0 +1,113 @@
+// 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/overlays/public/overlay_browser_agent_base.h"
+
+#include "base/logging.h"
+#import "ios/chrome/browser/main/browser.h"
+#include "ios/chrome/browser/overlays/public/overlay_request.h"
+#include "ios/chrome/browser/overlays/public/overlay_request_callback_installer.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#pragma mark - OverlayBrowserAgentBase
+
+OverlayBrowserAgentBase::OverlayBrowserAgentBase(Browser* browser)
+    : installation_driver_(browser, this) {}
+
+OverlayBrowserAgentBase::~OverlayBrowserAgentBase() = default;
+
+#pragma mark - Protected
+
+void OverlayBrowserAgentBase::AddInstaller(
+    std::unique_ptr<OverlayRequestCallbackInstaller> installer,
+    OverlayModality modality) {
+  DCHECK(installer);
+  CallbackInstallerStorage& storage = installer_storages_[modality];
+  storage.installers.push_back(std::move(installer));
+  // Reset the storage's request support to nullptr.  This will cause the
+  // aggregate support for all callback installers added for |modality| to be
+  // regenerated the next time GetRequestSupport() is called.
+  storage.request_support = nullptr;
+  // Notify the installation driver if this is the first installer added for
+  // |modality|.
+  if (storage.installers.size() == 1U)
+    installation_driver_.StartInstallingCallbacks(modality);
+}
+
+#pragma mark Private
+
+const OverlayRequestSupport* OverlayBrowserAgentBase::GetRequestSupport(
+    OverlayModality modality) {
+  CallbackInstallerStorage& storage = installer_storages_[modality];
+  if (!storage.request_support) {
+    const std::vector<std::unique_ptr<OverlayRequestCallbackInstaller>>&
+        installers = storage.installers;
+    std::vector<const OverlayRequestSupport*> supports(installers.size());
+    for (size_t index = 0; index < installers.size(); ++index) {
+      DCHECK(installers[index]->GetRequestSupport());
+      supports[index] = installers[index]->GetRequestSupport();
+    }
+    storage.request_support = std::make_unique<OverlayRequestSupport>(supports);
+  }
+  return storage.request_support.get();
+}
+
+void OverlayBrowserAgentBase::InstallOverlayRequestCallbacks(
+    OverlayRequest* request,
+    OverlayModality modality) {
+  for (auto& installer : installer_storages_[modality].installers) {
+    installer->InstallCallbacks(request);
+  }
+}
+
+#pragma mark - OverlayBrowserAgentBase::InstallationDriver
+
+OverlayBrowserAgentBase::CallbackInstallationDriver::CallbackInstallationDriver(
+    Browser* browser,
+    OverlayBrowserAgentBase* browser_agent)
+    : browser_(browser), browser_agent_(browser_agent), scoped_observer_(this) {
+  DCHECK(browser_agent_);
+  DCHECK(browser_);
+}
+
+OverlayBrowserAgentBase::CallbackInstallationDriver::
+    ~CallbackInstallationDriver() = default;
+
+void OverlayBrowserAgentBase::CallbackInstallationDriver::
+    StartInstallingCallbacks(OverlayModality modality) {
+  OverlayPresenter* presenter =
+      OverlayPresenter::FromBrowser(browser_, modality);
+  if (!scoped_observer_.IsObserving(presenter))
+    scoped_observer_.Add(presenter);
+}
+
+const OverlayRequestSupport*
+OverlayBrowserAgentBase::CallbackInstallationDriver::GetRequestSupport(
+    OverlayPresenter* presenter) const {
+  return browser_agent_->GetRequestSupport(presenter->GetModality());
+}
+
+void OverlayBrowserAgentBase::CallbackInstallationDriver::WillShowOverlay(
+    OverlayPresenter* presenter,
+    OverlayRequest* request) {
+  browser_agent_->InstallOverlayRequestCallbacks(request,
+                                                 presenter->GetModality());
+}
+
+void OverlayBrowserAgentBase::CallbackInstallationDriver::
+    OverlayPresenterDestroyed(OverlayPresenter* presenter) {
+  scoped_observer_.Remove(presenter);
+}
+
+#pragma mark - OverlayBrowserAgentBase::CallbackInstallerStorage
+
+OverlayBrowserAgentBase::CallbackInstallerStorage::CallbackInstallerStorage() =
+    default;
+
+OverlayBrowserAgentBase::CallbackInstallerStorage::~CallbackInstallerStorage() =
+    default;
diff --git a/ios/chrome/browser/overlays/overlay_browser_agent_base_unittest.mm b/ios/chrome/browser/overlays/overlay_browser_agent_base_unittest.mm
new file mode 100644
index 0000000..cbad54b
--- /dev/null
+++ b/ios/chrome/browser/overlays/overlay_browser_agent_base_unittest.mm
@@ -0,0 +1,166 @@
+// 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/overlays/public/overlay_browser_agent_base.h"
+
+#import "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
+#import "ios/chrome/browser/main/browser_user_data.h"
+#import "ios/chrome/browser/main/test_browser.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_callback_installer.h"
+#import "ios/chrome/browser/overlays/public/overlay_request_queue.h"
+#include "ios/chrome/browser/overlays/public/overlay_response.h"
+#include "ios/chrome/browser/overlays/test/fake_overlay_presentation_context.h"
+#include "ios/chrome/browser/overlays/test/fake_overlay_request_callback_installer.h"
+#include "ios/chrome/browser/overlays/test/overlay_test_macros.h"
+#import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
+#import "ios/chrome/browser/web_state_list/web_state_opener.h"
+#import "ios/web/public/test/fakes/test_web_state.h"
+#include "ios/web/public/test/web_task_environment.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
+
+namespace {
+// The modality to use in tests.
+const OverlayModality kModality = OverlayModality::kWebContentArea;
+// Request configs used in tests.
+DEFINE_TEST_OVERLAY_REQUEST_CONFIG(SupportedConfig);
+DEFINE_TEST_OVERLAY_REQUEST_CONFIG(UnsupportedConfig);
+DEFINE_TEST_OVERLAY_RESPONSE_INFO(DispatchInfo);
+
+// Fake version of OverlayBrowserAgentBase used for tests.
+class FakeOverlayBrowserAgent
+    : public OverlayBrowserAgentBase,
+      public BrowserUserData<FakeOverlayBrowserAgent> {
+ public:
+  // The mock callback receiver used by the FakeOverlayRequestCallbackInstaller
+  // whose callback installation is driven by the OverlayBrowserAgentBase
+  // superclass.
+  MockOverlayRequestCallbackReceiver& mock_callback_receiver() {
+    return mock_callback_receiver_;
+  }
+
+ private:
+  friend class BrowserUserData<FakeOverlayBrowserAgent>;
+  BROWSER_USER_DATA_KEY_DECL();
+
+  FakeOverlayBrowserAgent(Browser* browser) : OverlayBrowserAgentBase(browser) {
+    // Add a fake callback installer for kModality that supports requests
+    // configured with SupportedConfig and dispatched responses with
+    // DispatchInfo.
+    std::unique_ptr<FakeOverlayRequestCallbackInstaller> installer =
+        std::make_unique<FakeOverlayRequestCallbackInstaller>(
+            &mock_callback_receiver_);
+    installer->SetRequestSupport(SupportedConfig::RequestSupport());
+    installer->StartInstallingDispatchCallbacksWithSupport(
+        DispatchInfo::ResponseSupport());
+    AddInstaller(std::move(installer), kModality);
+  }
+
+  testing::StrictMock<MockOverlayRequestCallbackReceiver>
+      mock_callback_receiver_;
+};
+BROWSER_USER_DATA_KEY_IMPL(FakeOverlayBrowserAgent)
+}  // namespace
+
+// Test fixture for OverlayBrowserAgentBase.
+class OverlayBrowserAgentBaseTest : public PlatformTest {
+ public:
+  OverlayBrowserAgentBaseTest() : web_state_list_(&web_state_list_delegate_) {
+    // Create the Browser and set up the browser agent.
+    TestChromeBrowserState::Builder builder;
+    browser_state_ = builder.Build();
+    browser_ =
+        std::make_unique<TestBrowser>(browser_state_.get(), &web_state_list_);
+    FakeOverlayBrowserAgent::CreateForBrowser(browser_.get());
+    // Set up the infobar OverlayPresenter.
+    OverlayPresenter::FromBrowser(browser_.get(), kModality)
+        ->SetPresentationContext(&presentation_context_);
+    // Add and active a WebState over which to present overlays.
+    web_state_list_.InsertWebState(0, std::make_unique<web::TestWebState>(),
+                                   WebStateList::INSERT_ACTIVATE,
+                                   WebStateOpener());
+    web_state_ = web_state_list_.GetActiveWebState();
+  }
+
+  ~OverlayBrowserAgentBaseTest() override {
+    OverlayPresenter::FromBrowser(browser_.get(), kModality)
+        ->SetPresentationContext(nullptr);
+  }
+
+  // Returns the mock callback receiver for the browser agent.
+  MockOverlayRequestCallbackReceiver& mock_callback_receiver() {
+    return FakeOverlayBrowserAgent::FromBrowser(browser_.get())
+        ->mock_callback_receiver();
+  }
+
+  // Returns |web_state_|'s request queue.
+  OverlayRequestQueue* queue() {
+    return OverlayRequestQueue::FromWebState(web_state_, kModality);
+  }
+
+  // Cancels all requests in |web_state_|'s queue.
+  void CancelRequests() { queue()->CancelAllRequests(); }
+
+ protected:
+  web::WebTaskEnvironment task_environment_;
+  std::unique_ptr<ios::ChromeBrowserState> browser_state_;
+  FakeWebStateListDelegate web_state_list_delegate_;
+  WebStateList web_state_list_;
+  web::WebState* web_state_ = nullptr;
+  std::unique_ptr<Browser> browser_;
+  FakeOverlayPresentationContext presentation_context_;
+};
+
+// Tests that callbacks are successfully set up for supported requests.
+TEST_F(OverlayBrowserAgentBaseTest, SupportedRequestCallbackSetup) {
+  // Add a supported request to the queue so that its presentation is simulated
+  // in the fake presentation context, triggering the BrowserAgent to install
+  // its callbacks on the request.
+  std::unique_ptr<OverlayRequest> added_request =
+      OverlayRequest::CreateWithConfig<SupportedConfig>();
+  OverlayRequest* request = added_request.get();
+  queue()->AddRequest(std::move(added_request));
+
+  // Dispatch a response through this presented request, expecting the dispatch
+  // callback to be executed on the mock receiver.
+  std::unique_ptr<OverlayResponse> response =
+      OverlayResponse::CreateWithInfo<DispatchInfo>();
+  EXPECT_CALL(mock_callback_receiver(),
+              DispatchCallback(request, DispatchInfo::ResponseSupport(),
+                               response.get()));
+  request->GetCallbackManager()->DispatchResponse(std::move(response));
+
+  // Cancel the request, expecting the completion callback to be executed on the
+  // mock receiver.
+  EXPECT_CALL(mock_callback_receiver(), CompletionCallback(request, nullptr));
+  CancelRequests();
+}
+
+// Tests that callbacks are not executed for supported requests.
+TEST_F(OverlayBrowserAgentBaseTest, UnsupportedRequestCallbackSetup) {
+  // Add an unsupported request to the queue so that its presentation is
+  // simulated in the fake presentation context.  Since the added request is
+  // unsupported, no callbacks should have been installed.
+  std::unique_ptr<OverlayRequest> added_request =
+      OverlayRequest::CreateWithConfig<UnsupportedConfig>();
+  OverlayRequest* request = added_request.get();
+  queue()->AddRequest(std::move(added_request));
+
+  // Dispatch a response through this presented request without expecting the
+  // dispatch callback to be executed on the mock receiver.
+  std::unique_ptr<OverlayResponse> response =
+      OverlayResponse::CreateWithInfo<DispatchInfo>();
+  request->GetCallbackManager()->DispatchResponse(std::move(response));
+
+  // Cancel the request without expecting the completion callback to be executed
+  // on the mock receiver.
+  CancelRequests();
+}
diff --git a/ios/chrome/browser/overlays/overlay_presenter_impl.h b/ios/chrome/browser/overlays/overlay_presenter_impl.h
index 4894bbb..7426008 100644
--- a/ios/chrome/browser/overlays/overlay_presenter_impl.h
+++ b/ios/chrome/browser/overlays/overlay_presenter_impl.h
@@ -48,6 +48,7 @@
   };
 
   // OverlayPresenter:
+  OverlayModality GetModality() const override;
   void SetPresentationContext(
       OverlayPresentationContext* presentation_context) override;
   void AddObserver(OverlayPresenterObserver* observer) override;
diff --git a/ios/chrome/browser/overlays/overlay_presenter_impl.mm b/ios/chrome/browser/overlays/overlay_presenter_impl.mm
index 7bd338b..953cd59 100644
--- a/ios/chrome/browser/overlays/overlay_presenter_impl.mm
+++ b/ios/chrome/browser/overlays/overlay_presenter_impl.mm
@@ -77,6 +77,10 @@
 
 #pragma mark OverlayPresenter
 
+OverlayModality OverlayPresenterImpl::GetModality() const {
+  return modality_;
+}
+
 void OverlayPresenterImpl::SetPresentationContext(
     OverlayPresentationContext* presentation_context) {
   // When the presentation context is reset, the presenter will begin showing
diff --git a/ios/chrome/browser/overlays/overlay_request_callback_installer_unittest.cc b/ios/chrome/browser/overlays/overlay_request_callback_installer_unittest.cc
index 243c2a3..0f453c3 100644
--- a/ios/chrome/browser/overlays/overlay_request_callback_installer_unittest.cc
+++ b/ios/chrome/browser/overlays/overlay_request_callback_installer_unittest.cc
@@ -18,20 +18,6 @@
 DEFINE_TEST_OVERLAY_REQUEST_CONFIG(UnsupportedConfig);
 DEFINE_TEST_OVERLAY_RESPONSE_INFO(DispatchInfo);
 DEFINE_TEST_OVERLAY_RESPONSE_INFO(CompletionInfo);
-
-// Mock callback receiver.
-class MockCallbackReceiver : public FakeOverlayRequestCallbackReceiver {
- public:
-  MockCallbackReceiver() = default;
-  ~MockCallbackReceiver() = default;
-
-  MOCK_METHOD2(CompletionCallback,
-               void(OverlayRequest* request, OverlayResponse* response));
-  MOCK_METHOD3(DispatchCallback,
-               void(OverlayRequest* request,
-                    const OverlayResponseSupport* response_support,
-                    OverlayResponse* response));
-};
 }  // namespace
 
 // Test fixture for OverlayRequestCallbackInstaller.
@@ -60,7 +46,7 @@
   }
 
  protected:
-  testing::StrictMock<MockCallbackReceiver> mock_receiver_;
+  testing::StrictMock<MockOverlayRequestCallbackReceiver> mock_receiver_;
   FakeOverlayRequestCallbackInstaller installer_;
 };
 
diff --git a/ios/chrome/browser/overlays/public/overlay_browser_agent_base.h b/ios/chrome/browser/overlays/public/overlay_browser_agent_base.h
new file mode 100644
index 0000000..1795048
--- /dev/null
+++ b/ios/chrome/browser/overlays/public/overlay_browser_agent_base.h
@@ -0,0 +1,92 @@
+// 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_OVERLAYS_PUBLIC_OVERLAY_BROWSER_AGENT_BASE_H_
+#define IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_OVERLAY_BROWSER_AGENT_BASE_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/scoped_observer.h"
+#include "ios/chrome/browser/overlays/public/overlay_presenter.h"
+#include "ios/chrome/browser/overlays/public/overlay_presenter_observer.h"
+#include "ios/chrome/browser/overlays/public/overlay_request_callback_installer.h"
+#include "ios/chrome/browser/overlays/public/overlay_request_support.h"
+
+// Browser agent class, intended to be subclassed, that installs callbacks for
+// OverlayRequests in order to make model-layer updates for interaction with
+// overlay UI.  Used to combine model-layer logic between OverlayRequests with
+// shared functionality but different OverlayRequestConfigs (e.g. an action
+// sheet and alert overlay that both update the same model object).  Subclasses
+// should also specialize the BrowserUserData template so each subclass has its
+// own unique key.
+class OverlayBrowserAgentBase {
+ public:
+  virtual ~OverlayBrowserAgentBase();
+
+ protected:
+  // Constructor to be called by subclasses.
+  explicit OverlayBrowserAgentBase(Browser* browser);
+
+  // Called by subclasses in order to install callbacks using |installer| on
+  // supported OverlayRequests at |modality|.  |installer| must be non-null.
+  void AddInstaller(std::unique_ptr<OverlayRequestCallbackInstaller> installer,
+                    OverlayModality modality);
+
+  // Returns the aggregate request support for all callback installers added
+  // for |modality|.
+  const OverlayRequestSupport* GetRequestSupport(OverlayModality modality);
+
+ private:
+  // Installs the callbacks for |request| using the installers added via
+  // AddInstaller() for |modality|.
+  void InstallOverlayRequestCallbacks(OverlayRequest* request,
+                                      OverlayModality modality);
+
+  // Helper object that drives the installation of callbacks for each
+  // OverlayRequest upon the first presentation of its overlay UI.
+  class CallbackInstallationDriver : public OverlayPresenterObserver {
+   public:
+    // Constructor for an installation driver for OverlayRequests presented via
+    // |browser|'s OverlayPresenters.
+    CallbackInstallationDriver(Browser* browser,
+                               OverlayBrowserAgentBase* browser_agent);
+    ~CallbackInstallationDriver() override;
+
+    // Starts driving the BrowserAgent's installation of callbacks for requests
+    // whose UI is presented from |modality|'s presenter.
+    void StartInstallingCallbacks(OverlayModality modality);
+
+   private:
+    // OverlayPresenterObserver:
+    const OverlayRequestSupport* GetRequestSupport(
+        OverlayPresenter* presenter) const override;
+    void WillShowOverlay(OverlayPresenter* presenter,
+                         OverlayRequest* request) override;
+    void OverlayPresenterDestroyed(OverlayPresenter* presenter) override;
+
+    Browser* browser_ = nullptr;
+    OverlayBrowserAgentBase* browser_agent_ = nullptr;
+    ScopedObserver<OverlayPresenter, OverlayPresenterObserver> scoped_observer_;
+  };
+
+  // Storage struct used to store OverlayRequestCallbackInstallers and their
+  // aggregated support for each OverlayModality.
+  struct CallbackInstallerStorage {
+    CallbackInstallerStorage();
+    ~CallbackInstallerStorage();
+    // The callback installers
+    std::vector<std::unique_ptr<OverlayRequestCallbackInstaller>> installers;
+    // The aggregate support for all added installers.
+    std::unique_ptr<OverlayRequestSupport> request_support;
+  };
+
+  // Map containing the list of OverlayRequestCallbackInstallers for each
+  // OverlayModality.
+  std::map<OverlayModality, CallbackInstallerStorage> installer_storages_;
+  // The callback installation driver.
+  CallbackInstallationDriver installation_driver_;
+};
+
+#endif  // IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_OVERLAY_BROWSER_AGENT_BASE_H_
diff --git a/ios/chrome/browser/overlays/public/overlay_presenter.h b/ios/chrome/browser/overlays/public/overlay_presenter.h
index 22d7d15..f327a66 100644
--- a/ios/chrome/browser/overlays/public/overlay_presenter.h
+++ b/ios/chrome/browser/overlays/public/overlay_presenter.h
@@ -24,6 +24,9 @@
   static OverlayPresenter* FromBrowser(Browser* browser,
                                        OverlayModality modality);
 
+  // Returns the presenter's modality.
+  virtual OverlayModality GetModality() const = 0;
+
   // Sets the presentation context in which to show overlay UI.  Upon being set,
   // the presenter will attempt to begin presenting overlay UI for the active
   // WebState in its Browser.
diff --git a/ios/chrome/browser/overlays/public/overlay_request_callback_installer.h b/ios/chrome/browser/overlays/public/overlay_request_callback_installer.h
index f4991be..c4500633 100644
--- a/ios/chrome/browser/overlays/public/overlay_request_callback_installer.h
+++ b/ios/chrome/browser/overlays/public/overlay_request_callback_installer.h
@@ -24,12 +24,12 @@
   // supported request if called more than once.  |request| must be non-null.
   void InstallCallbacks(OverlayRequest* request);
 
- protected:
   // Returns the request support for this installer.  InstallCallbacksInternal()
   // will only be called for supported requests.  By default, all requests are
   // supported.
   virtual const OverlayRequestSupport* GetRequestSupport() const;
 
+ protected:
   // Called from InstallCallbacks() if |request| is supported by
   // GetRequestSupport().  Subclasses should override to supply callbacks for a
   // specific kind of request.  Does nothing by default.
diff --git a/ios/chrome/browser/overlays/test/BUILD.gn b/ios/chrome/browser/overlays/test/BUILD.gn
index d1c349c3..12a6b72 100644
--- a/ios/chrome/browser/overlays/test/BUILD.gn
+++ b/ios/chrome/browser/overlays/test/BUILD.gn
@@ -19,6 +19,7 @@
   deps = [
     "//base",
     "//ios/chrome/browser/overlays",
+    "//testing/gmock",
     "//testing/gtest",
   ]
 }
diff --git a/ios/chrome/browser/overlays/test/fake_overlay_request_callback_installer.cc b/ios/chrome/browser/overlays/test/fake_overlay_request_callback_installer.cc
index 743f55d..9bafc46 100644
--- a/ios/chrome/browser/overlays/test/fake_overlay_request_callback_installer.cc
+++ b/ios/chrome/browser/overlays/test/fake_overlay_request_callback_installer.cc
@@ -12,6 +12,16 @@
 #include "ios/chrome/browser/overlays/public/overlay_request_support.h"
 #include "ios/chrome/browser/overlays/public/overlay_response_support.h"
 
+#pragma mark - MockOverlayRequestCallbackReceiver
+
+MockOverlayRequestCallbackReceiver::MockOverlayRequestCallbackReceiver() =
+    default;
+
+MockOverlayRequestCallbackReceiver::~MockOverlayRequestCallbackReceiver() =
+    default;
+
+#pragma mark - FakeOverlayRequestCallbackInstaller
+
 FakeOverlayRequestCallbackInstaller::FakeOverlayRequestCallbackInstaller(
     FakeOverlayRequestCallbackReceiver* receiver)
     : receiver_(receiver), request_support_(OverlayRequestSupport::All()) {
diff --git a/ios/chrome/browser/overlays/test/fake_overlay_request_callback_installer.h b/ios/chrome/browser/overlays/test/fake_overlay_request_callback_installer.h
index 2a646ec..0c8d82d 100644
--- a/ios/chrome/browser/overlays/test/fake_overlay_request_callback_installer.h
+++ b/ios/chrome/browser/overlays/test/fake_overlay_request_callback_installer.h
@@ -8,6 +8,7 @@
 #include <set>
 
 #include "ios/chrome/browser/overlays/public/overlay_request_callback_installer.h"
+#include "testing/gmock/include/gmock/gmock.h"
 
 class OverlayResponseSupport;
 
@@ -26,6 +27,21 @@
                                 OverlayResponse* response) = 0;
 };
 
+// Mock version of the fake callback receiver receiver.
+class MockOverlayRequestCallbackReceiver
+    : public FakeOverlayRequestCallbackReceiver {
+ public:
+  MockOverlayRequestCallbackReceiver();
+  ~MockOverlayRequestCallbackReceiver();
+
+  MOCK_METHOD2(CompletionCallback,
+               void(OverlayRequest* request, OverlayResponse* response));
+  MOCK_METHOD3(DispatchCallback,
+               void(OverlayRequest* request,
+                    const OverlayResponseSupport* response_support,
+                    OverlayResponse* response));
+};
+
 // OverlayRequestCallbackInstaller subclass used for testing.  Sets up callbacks
 // that execute on a mocked receiver that is exposed for testing.
 class FakeOverlayRequestCallbackInstaller
diff --git a/ios/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.mm b/ios/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.mm
index 640d290..f8c68205 100644
--- a/ios/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.mm
+++ b/ios/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.mm
@@ -5,7 +5,7 @@
 #include "ios/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.h"
 
 #include "components/autofill/core/browser/logging/log_router.h"
-#include "components/grit/components_resources.h"
+#include "components/grit/dev_ui_components_resources.h"
 #include "components/version_info/version_info.h"
 #include "components/version_ui/version_handler_helper.h"
 #include "components/version_ui/version_ui_constants.h"
diff --git a/ios/chrome/browser/ui/webui/crashes_ui.cc b/ios/chrome/browser/ui/webui/crashes_ui.cc
index 24c894c..04ed02a 100644
--- a/ios/chrome/browser/ui/webui/crashes_ui.cc
+++ b/ios/chrome/browser/ui/webui/crashes_ui.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 
 #include <memory>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -15,7 +16,7 @@
 #include "base/system/sys_info.h"
 #include "base/values.h"
 #include "components/crash/core/browser/crashes_ui_util.h"
-#include "components/grit/components_resources.h"
+#include "components/grit/dev_ui_components_resources.h"
 #include "components/strings/grit/components_chromium_strings.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/version_info/version_info.h"
diff --git a/ios/chrome/browser/ui/webui/gcm/gcm_internals_ui.cc b/ios/chrome/browser/ui/webui/gcm/gcm_internals_ui.cc
index 325e040..514b6b26 100644
--- a/ios/chrome/browser/ui/webui/gcm/gcm_internals_ui.cc
+++ b/ios/chrome/browser/ui/webui/gcm/gcm_internals_ui.cc
@@ -17,7 +17,7 @@
 #include "components/gcm_driver/gcm_internals_constants.h"
 #include "components/gcm_driver/gcm_internals_helper.h"
 #include "components/gcm_driver/gcm_profile_service.h"
-#include "components/grit/components_resources.h"
+#include "components/grit/dev_ui_components_resources.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #include "ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.h"
diff --git a/ios/chrome/browser/ui/webui/net_export/net_export_ui.mm b/ios/chrome/browser/ui/webui/net_export/net_export_ui.mm
index 89bc3b28..f249c49 100644
--- a/ios/chrome/browser/ui/webui/net_export/net_export_ui.mm
+++ b/ios/chrome/browser/ui/webui/net_export/net_export_ui.mm
@@ -13,7 +13,7 @@
 #include "base/scoped_observer.h"
 #include "base/strings/string_util.h"
 #include "base/values.h"
-#include "components/grit/components_resources.h"
+#include "components/grit/dev_ui_components_resources.h"
 #include "components/net_log/net_export_file_writer.h"
 #include "components/net_log/net_export_ui_constants.h"
 #include "ios/chrome/browser/application_context.h"
diff --git a/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc b/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
index bf6963e..653c5ed 100644
--- a/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
+++ b/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
@@ -5,8 +5,9 @@
 #include "ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.h"
 
 #include <memory>
+#include <vector>
 
-#include "components/grit/components_resources.h"
+#include "components/grit/dev_ui_components_resources.h"
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/ntp_tiles/most_visited_sites.h"
 #include "components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h"
diff --git a/ios/chrome/browser/ui/webui/signin_internals_ui_ios.cc b/ios/chrome/browser/ui/webui/signin_internals_ui_ios.cc
index 27eb365..172155f 100644
--- a/ios/chrome/browser/ui/webui/signin_internals_ui_ios.cc
+++ b/ios/chrome/browser/ui/webui/signin_internals_ui_ios.cc
@@ -4,8 +4,11 @@
 
 #include "ios/chrome/browser/ui/webui/signin_internals_ui_ios.h"
 
+#include <string>
+#include <vector>
+
 #include "base/hash/hash.h"
-#include "components/grit/components_resources.h"
+#include "components/grit/dev_ui_components_resources.h"
 #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
diff --git a/ios/chrome/browser/ui/webui/user_actions_ui.mm b/ios/chrome/browser/ui/webui/user_actions_ui.mm
index c19ca45..b1d7c4a 100644
--- a/ios/chrome/browser/ui/webui/user_actions_ui.mm
+++ b/ios/chrome/browser/ui/webui/user_actions_ui.mm
@@ -4,7 +4,7 @@
 
 #include "ios/chrome/browser/ui/webui/user_actions_ui.h"
 
-#include "components/grit/components_resources.h"
+#include "components/grit/dev_ui_components_resources.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #include "ios/chrome/browser/ui/webui/user_actions_handler.h"
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn
index eebe57d..a91c0d10 100644
--- a/ios/chrome/browser/web/BUILD.gn
+++ b/ios/chrome/browser/web/BUILD.gn
@@ -35,6 +35,7 @@
     "//components/error_page/common",
     "//components/image_fetcher/ios",
     "//components/resources:components_resources_grit",
+    "//components/resources:dev_ui_components_resources_grit",
     "//components/search_engines",
     "//components/strings",
     "//ios/chrome/app/strings:ios_strings_grit",
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h
index 0ca3695e..64aaa9a 100644
--- a/ipc/ipc_message_start.h
+++ b/ipc/ipc_message_start.h
@@ -33,7 +33,6 @@
   AccessibilityMsgStart,
   PrerenderMsgStart,
   ChromotingMsgStart,
-  BrowserPluginMsgStart,
   AndroidWebViewMsgStart,
   NaClHostMsgStart,
   EncryptedMediaMsgStart,
@@ -42,7 +41,6 @@
   ChromeUtilityPrintingMsgStart,
   OzoneGpuMsgStart,
   WebTestMsgStart,
-  NetworkHintsMsgStart,
   ExtensionsGuestViewMsgStart,
   GuestViewMsgStart,
   MediaPlayerDelegateMsgStart,
diff --git a/media/BUILD.gn b/media/BUILD.gn
index ac85bccb..fe59a4e 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -162,7 +162,9 @@
     "test/data/",
   ]
 
-  data_deps = []
+  data_deps = [
+    "//testing/buildbot/filters:media_unittests_filters",
+  ]
 
   if (media_use_ffmpeg) {
     deps += [ "//media/ffmpeg:unit_tests" ]
diff --git a/media/base/win/dxgi_device_scope_handle_unittest.cc b/media/base/win/dxgi_device_scope_handle_unittest.cc
index a5fc44d3..85ca183 100644
--- a/media/base/win/dxgi_device_scope_handle_unittest.cc
+++ b/media/base/win/dxgi_device_scope_handle_unittest.cc
@@ -5,6 +5,7 @@
 #include <d3d11.h>
 #include <mfapi.h>
 
+#include "base/win/windows_version.h"
 #include "media/base/test_helpers.h"
 #include "media/base/win/mf_helpers.h"
 #include "media/base/win/mf_initializer.h"
@@ -15,11 +16,15 @@
 
 class DXGIDeviceScopedHandleTest : public testing::Test {
  public:
-  DXGIDeviceScopedHandleTest() = default;
+  DXGIDeviceScopedHandleTest()
+      : test_supported_(base::win::GetVersion() >= base::win::Version::WIN10) {}
   ~DXGIDeviceScopedHandleTest() override = default;
 
  protected:
   void SetUp() override {
+    if (!test_supported_)
+      return;
+
     ASSERT_TRUE(InitializeMediaFoundation());
 
     // Get a shared DXGI Device Manager from Media Foundation.
@@ -50,16 +55,23 @@
   }
 
   void TearDown() override {
-    ASSERT_HRESULT_SUCCEEDED(MFUnlockDXGIDeviceManager());
+    if (test_supported_) {
+      ASSERT_HRESULT_SUCCEEDED(MFUnlockDXGIDeviceManager());
+    }
   }
 
   Microsoft::WRL::ComPtr<IMFDXGIDeviceManager> dxgi_device_man_ = nullptr;
   UINT device_reset_token_ = 0;
+  const bool test_supported_;
 };
 
 TEST_F(DXGIDeviceScopedHandleTest, UseDXGIDeviceScopedHandle) {
+  if (!test_supported_)
+    return;
+
   {
-    // Create DXGIDeviceScopedHandle in an inner scope without LockDevice call.
+    // Create DXGIDeviceScopedHandle in an inner scope without LockDevice
+    // call.
     mf::DXGIDeviceScopedHandle device_handle_1(dxgi_device_man_.Get());
   }
   {
diff --git a/media/fuchsia/audio/fuchsia_audio_renderer.cc b/media/fuchsia/audio/fuchsia_audio_renderer.cc
index 378301ac..a7cd9af7 100644
--- a/media/fuchsia/audio/fuchsia_audio_renderer.cc
+++ b/media/fuchsia/audio/fuchsia_audio_renderer.cc
@@ -233,15 +233,20 @@
     flags = fuchsia::media::AudioConsumerStartFlags::LOW_LATENCY;
   }
 
+  bool send_stop = false;
   base::TimeDelta media_pos;
   {
     base::AutoLock lock(state_lock_);
     media_pos = media_pos_;
+    send_stop = state_ != PlaybackState::kStopped;
     state_ = PlaybackState::kStarting;
   }
 
-  audio_consumer_->Start(flags, media_pos.ToZxDuration(),
-                         fuchsia::media::NO_TIMESTAMP);
+  if (send_stop)
+    audio_consumer_->Stop();
+
+  audio_consumer_->Start(flags, fuchsia::media::NO_TIMESTAMP,
+                         media_pos.ToZxDuration());
 }
 
 void FuchsiaAudioRenderer::StopTicking() {
diff --git a/media/fuchsia/audio/fuchsia_audio_renderer.h b/media/fuchsia/audio/fuchsia_audio_renderer.h
index a4e6f90..2b11702 100644
--- a/media/fuchsia/audio/fuchsia_audio_renderer.h
+++ b/media/fuchsia/audio/fuchsia_audio_renderer.h
@@ -138,8 +138,11 @@
   base::TimeDelta min_lead_time_;
   base::TimeDelta max_lead_time_;
 
-  // TimeSource interface is not single-threaded. It's used to guard fields
-  // that area accessed in the TimeSource implementation.
+  // TimeSource interface is not single-threaded. The lock is used to guard
+  // fields that are accessed in the TimeSource implementation. Note that these
+  // fields are updated only on the main thread (which corresponds to the
+  // |thread_checker_|), so on that thread it's safe to assume that the values
+  // don't change even when not holding the lock.
   base::Lock state_lock_;
 
   PlaybackState state_ GUARDED_BY(state_lock_) = PlaybackState::kStopped;
diff --git a/mojo/core/BUILD.gn b/mojo/core/BUILD.gn
index a132c938..ad65243 100644
--- a/mojo/core/BUILD.gn
+++ b/mojo/core/BUILD.gn
@@ -377,10 +377,8 @@
     args = [
       "--encode=mojo_fuzzer.ChannelMac",
       "-I",
-      rebase_path("//testing/libfuzzer/fuzzers/mach"),
-      "-I",
-      rebase_path("//mojo/core/test/data/channel_mac"),
-      "channel_mac.proto",
+      rebase_path("//"),
+      "mojo/core/test/data/channel_mac/channel_mac.proto",
     ]
   }
 
diff --git a/mojo/core/test/BUILD.gn b/mojo/core/test/BUILD.gn
index 5e18e027..d907d3f 100644
--- a/mojo/core/test/BUILD.gn
+++ b/mojo/core/test/BUILD.gn
@@ -91,12 +91,10 @@
 
 if (is_mac) {
   proto_library("channel_mac_proto") {
+    proto_in_dir = "//"
     sources = [
       "data/channel_mac/channel_mac.proto",
     ]
-    deps = [
-      "//testing/libfuzzer/fuzzers/mach:proto",
-    ]
-    import_dirs = [ "//testing/libfuzzer/fuzzers/mach" ]
+    link_deps = [ "//testing/libfuzzer/fuzzers/mach:proto" ]
   }
 }
diff --git a/mojo/core/test/data/channel_mac/channel_mac.proto b/mojo/core/test/data/channel_mac/channel_mac.proto
index 64b70adb..a790579e 100644
--- a/mojo/core/test/data/channel_mac/channel_mac.proto
+++ b/mojo/core/test/data/channel_mac/channel_mac.proto
@@ -6,7 +6,7 @@
 
 package mojo_fuzzer;
 
-import "mach_message.proto";
+import "testing/libfuzzer/fuzzers/mach/mach_message.proto";
 
 // Extension to MachMessage that enables fuzzing the internal structure of
 // the Mojo message data.
diff --git a/mojo/public/tools/.style.yapf b/mojo/public/tools/.style.yapf
new file mode 100644
index 0000000..b4ebbe2
--- /dev/null
+++ b/mojo/public/tools/.style.yapf
@@ -0,0 +1,6 @@
+[style]
+based_on_style = pep8
+
+# New directories should use a .style.yapf that does not include the following:
+column_limit = 80
+indent_width = 2
diff --git a/net/base/net_errors.cc b/net/base/net_errors.cc
index ed6bc4514..7e7ee37ac 100644
--- a/net/base/net_errors.cc
+++ b/net/base/net_errors.cc
@@ -63,8 +63,8 @@
 }
 
 bool IsDnsError(int error) {
-  return (error == ERR_NAME_NOT_RESOLVED ||
-          error == ERR_NAME_RESOLUTION_FAILED);
+  DCHECK_NE(ERR_NAME_RESOLUTION_FAILED, error);
+  return error == ERR_NAME_NOT_RESOLVED;
 }
 
 Error FileErrorToNetError(base::File::Error file_error) {
diff --git a/net/dns/host_resolver.h b/net/dns/host_resolver.h
index 092ac6f..264ab583 100644
--- a/net/dns/host_resolver.h
+++ b/net/dns/host_resolver.h
@@ -66,12 +66,9 @@
     // On any other returned value, the request was handled synchronously and
     // |callback| will not be invoked.
     //
-    // Results in ERR_NAME_NOT_RESOLVED if the hostname is invalid, or if it is
-    // an incompatible IP literal (e.g. IPv6 is disabled and it is an IPv6
-    // literal).
-    //
-    // Results in ERR_DNS_CACHE_MISS if only fast local sources are to be
-    // queried and a cache lookup attempt fails.
+    // Results in ERR_NAME_NOT_RESOLVED if the hostname is not resolved. More
+    // detail about the underlying error can be retrieved using
+    // GetResolveErrorInfo().
     //
     // The parent HostResolver must still be alive when Start() is called,  but
     // if it is destroyed before an asynchronous result completes, the request
diff --git a/net/dns/host_resolver_manager.cc b/net/dns/host_resolver_manager.cc
index 795386a..a98331a 100644
--- a/net/dns/host_resolver_manager.cc
+++ b/net/dns/host_resolver_manager.cc
@@ -650,7 +650,7 @@
     LogFinishRequest(error);
 
     DCHECK(callback_);
-    std::move(callback_).Run(error);
+    std::move(callback_).Run(HostResolver::SquashErrorCode(error));
   }
 
   Job* job() const { return job_; }
@@ -2992,7 +2992,7 @@
                     effective_secure_dns_mode, base::TimeDelta());
     request->set_error_info(results.error(),
                             false /* is_secure_network_error */);
-    return results.error();
+    return HostResolver::SquashErrorCode(results.error());
   }
 
   CreateAndStartJob(effective_query_type, effective_host_resolver_flags,
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc
index ef064ee..ee9b6042 100644
--- a/net/nqe/network_quality_estimator.cc
+++ b/net/nqe/network_quality_estimator.cc
@@ -544,16 +544,6 @@
                            : "NQE.WifiSignalStrength.LevelAvailable";
 
     base::UmaHistogramBoolean(histogram_name, signal_strength_available);
-
-    if (signal_strength_available) {
-      std::string histogram_name =
-          is_cell_connection ? "NQE.CellularSignalStrength.LevelDifference"
-                             : "NQE.WifiSignalStrength.LevelDifference";
-      base::UmaHistogramCounts100(
-          histogram_name,
-          max_signal_strength_since_connection_change_.value() -
-              min_signal_strength_since_connection_change_.value());
-    }
   }
 #endif  // OS_ANDROID
   current_network_id_.signal_strength = INT32_MIN;
diff --git a/net/url_request/http_with_dns_over_https_unittest.cc b/net/url_request/http_with_dns_over_https_unittest.cc
index 12fe95c0..d4f1d9e 100644
--- a/net/url_request/http_with_dns_over_https_unittest.cc
+++ b/net/url_request/http_with_dns_over_https_unittest.cc
@@ -313,7 +313,7 @@
   EXPECT_EQ(test_https_requests_served_, 0u);
 
   EXPECT_TRUE(d.response_completed());
-  EXPECT_EQ(d.request_status(), net::ERR_DNS_MALFORMED_RESPONSE);
+  EXPECT_EQ(d.request_status(), net::ERR_NAME_NOT_RESOLVED);
 
   const auto& resolve_error_info = req->response_info().resolve_error_info;
   EXPECT_TRUE(resolve_error_info.is_secure_network_error);
diff --git a/printing/backend/cups_helper.cc b/printing/backend/cups_helper.cc
index 039d8f0..87c61b4a 100644
--- a/printing/backend/cups_helper.cc
+++ b/printing/backend/cups_helper.cc
@@ -50,6 +50,11 @@
 constexpr char kBrotherMonoColor[] = "BRMonoColor";
 constexpr char kBrotherPrintQuality[] = "BRPrintQuality";
 
+// HP printer specific options.
+constexpr char kHpColorMode[] = "HPColorMode";
+constexpr char kHpColorPrint[] = "ColorPrint";
+constexpr char kHpGrayscalePrint[] = "GrayscalePrint";
+
 // Samsung printer specific options.
 constexpr char kSamsungColorTrue[] = "True";
 constexpr char kSamsungColorFalse[] = "False";
@@ -318,7 +323,7 @@
                         ColorModel* color_model_for_black,
                         ColorModel* color_model_for_color,
                         bool* color_is_default) {
-  // HP printers use "Color/Color Model" attribute in their PPDs.
+  // Some HP printers use "Color/Color Model" attribute in their PPDs.
   ppd_option_t* color_mode_option = ppdFindOption(ppd, kColor);
   if (!color_mode_option)
     return false;
@@ -339,6 +344,32 @@
   return true;
 }
 
+bool GetHPColorModeSettings(ppd_file_t* ppd,
+                            ColorModel* color_model_for_black,
+                            ColorModel* color_model_for_color,
+                            bool* color_is_default) {
+  // Some HP printers use "HPColorMode/Mode" attribute in their PPDs.
+  ppd_option_t* color_mode_option = ppdFindOption(ppd, kHpColorMode);
+  if (!color_mode_option)
+    return false;
+
+  if (ppdFindChoice(color_mode_option, kHpColorPrint))
+    *color_model_for_color = HP_COLOR_COLOR;
+  if (ppdFindChoice(color_mode_option, kHpGrayscalePrint))
+    *color_model_for_black = HP_COLOR_BLACK;
+
+  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kHpColorMode);
+  if (!mode_choice) {
+    mode_choice =
+        ppdFindChoice(color_mode_option, color_mode_option->defchoice);
+  }
+  if (mode_choice) {
+    *color_is_default =
+        EqualsCaseInsensitiveASCII(mode_choice->choice, kHpColorPrint);
+  }
+  return true;
+}
+
 bool GetProcessColorModelSettings(ppd_file_t* ppd,
                                   ColorModel* color_model_for_black,
                                   ColorModel* color_model_for_color,
@@ -384,6 +415,7 @@
          GetPrintOutModeColorSettings(ppd, cm_black, cm_color, is_color) ||
          GetColorModeSettings(ppd, cm_black, cm_color, is_color) ||
          GetHPColorSettings(ppd, cm_black, cm_color, is_color) ||
+         GetHPColorModeSettings(ppd, cm_black, cm_color, is_color) ||
          GetBrotherColorSettings(ppd, cm_black, cm_color, is_color) ||
          GetProcessColorModelSettings(ppd, cm_black, cm_color, is_color);
 }
diff --git a/printing/backend/cups_helper_unittest.cc b/printing/backend/cups_helper_unittest.cc
index 11952a2..ca91283 100644
--- a/printing/backend/cups_helper_unittest.cc
+++ b/printing/backend/cups_helper_unittest.cc
@@ -318,6 +318,28 @@
   }
 }
 
+TEST(PrintBackendCupsHelperTest, TestPpdParsingHpPrinters) {
+  {
+    constexpr char kTestPpdData[] =
+        R"(*PPD-Adobe: "4.3"
+*ColorDevice: True
+*OpenUI *HPColorMode/Mode: PickOne
+*DefaultHPColorMode: ColorPrint
+*HPColorMode ColorPrint/Color: "
+  << /ProcessColorModel /DeviceCMYK >> setpagedevice"
+*HPColorMode GrayscalePrint/Grayscale: "
+  << /ProcessColorModel /DeviceGray >> setpagedevice"
+*CloseUI: *HPColorMode)";
+
+    PrinterSemanticCapsAndDefaults caps;
+    EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
+    EXPECT_TRUE(caps.color_changeable);
+    EXPECT_TRUE(caps.color_default);
+    EXPECT_EQ(HP_COLOR_COLOR, caps.color_model);
+    EXPECT_EQ(HP_COLOR_BLACK, caps.bw_model);
+  }
+}
+
 TEST(PrintBackendCupsHelperTest, TestPpdParsingSamsungPrinters) {
   {
     constexpr char kTestPpdData[] =
diff --git a/services/data_decoder/public/cpp/BUILD.gn b/services/data_decoder/public/cpp/BUILD.gn
index a2e0515..69f3a06 100644
--- a/services/data_decoder/public/cpp/BUILD.gn
+++ b/services/data_decoder/public/cpp/BUILD.gn
@@ -84,6 +84,12 @@
   sources = [
     "test_support/in_process_data_decoder.cc",
     "test_support/in_process_data_decoder.h",
+    "test_support/web_bundle_builder.cc",
+    "test_support/web_bundle_builder.h",
+  ]
+
+  deps = [
+    "//components/cbor",
   ]
 
   public_deps = [
diff --git a/services/data_decoder/public/cpp/test_support/web_bundle_builder.cc b/services/data_decoder/public/cpp/test_support/web_bundle_builder.cc
new file mode 100644
index 0000000..8155e97
--- /dev/null
+++ b/services/data_decoder/public/cpp/test_support/web_bundle_builder.cc
@@ -0,0 +1,149 @@
+// 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 "services/data_decoder/public/cpp/test_support/web_bundle_builder.h"
+
+namespace data_decoder {
+namespace test {
+
+namespace {
+
+cbor::Value CreateByteString(base::StringPiece s) {
+  return cbor::Value(base::as_bytes(base::make_span(s)));
+}
+
+cbor::Value CreateHeaderMap(const WebBundleBuilder::Headers& headers) {
+  cbor::Value::MapValue map;
+  for (const auto& pair : headers)
+    map.insert({CreateByteString(pair.first), CreateByteString(pair.second)});
+  return cbor::Value(std::move(map));
+}
+
+}  // namespace
+
+WebBundleBuilder::WebBundleBuilder(const std::string& fallback_url,
+                                   const std::string& manifest_url)
+    : fallback_url_(fallback_url) {
+  writer_config_.allow_invalid_utf8_for_testing = true;
+  if (!manifest_url.empty()) {
+    AddSection("manifest",
+               cbor::Value::InvalidUTF8StringValueForTesting(manifest_url));
+  }
+}
+
+WebBundleBuilder::~WebBundleBuilder() = default;
+
+void WebBundleBuilder::AddExchange(base::StringPiece url,
+                                   const Headers& response_headers,
+                                   base::StringPiece payload) {
+  AddIndexEntry(url, "", {AddResponse(response_headers, payload)});
+}
+
+WebBundleBuilder::ResponseLocation WebBundleBuilder::AddResponse(
+    const Headers& headers,
+    base::StringPiece payload) {
+  // We assume that the size of the CBOR header of the responses array is 1,
+  // which is true only if the responses array has no more than 23 elements.
+  DCHECK_LT(responses_.size(), 23u)
+      << "WebBundleBuilder cannot create bundles with more than 23 responses";
+
+  cbor::Value::ArrayValue response_array;
+  response_array.emplace_back(Encode(CreateHeaderMap(headers)));
+  response_array.emplace_back(CreateByteString(payload));
+  cbor::Value response(response_array);
+  int64_t response_length = EncodedLength(response);
+  ResponseLocation result = {current_responses_offset_, response_length};
+  current_responses_offset_ += response_length;
+  responses_.emplace_back(std::move(response));
+  return result;
+}
+
+void WebBundleBuilder::AddIndexEntry(
+    base::StringPiece url,
+    base::StringPiece variants_value,
+    std::vector<ResponseLocation> response_locations) {
+  cbor::Value::ArrayValue index_value_array;
+  index_value_array.emplace_back(CreateByteString(variants_value));
+  for (const auto& location : response_locations) {
+    index_value_array.emplace_back(location.offset);
+    index_value_array.emplace_back(location.length);
+  }
+  index_.insert({cbor::Value::InvalidUTF8StringValueForTesting(url),
+                 cbor::Value(index_value_array)});
+}
+
+void WebBundleBuilder::AddSection(base::StringPiece name, cbor::Value section) {
+  section_lengths_.emplace_back(name);
+  section_lengths_.emplace_back(EncodedLength(section));
+  sections_.emplace_back(std::move(section));
+}
+
+void WebBundleBuilder::AddAuthority(cbor::Value::MapValue authority) {
+  authorities_.emplace_back(std::move(authority));
+}
+
+void WebBundleBuilder::AddVouchedSubset(cbor::Value::MapValue vouched_subset) {
+  vouched_subsets_.emplace_back(std::move(vouched_subset));
+}
+
+std::vector<uint8_t> WebBundleBuilder::CreateBundle() {
+  AddSection("index", cbor::Value(index_));
+  if (!authorities_.empty() || !vouched_subsets_.empty()) {
+    cbor::Value::ArrayValue signatures_section;
+    signatures_section.emplace_back(std::move(authorities_));
+    signatures_section.emplace_back(std::move(vouched_subsets_));
+    AddSection("signatures", cbor::Value(std::move(signatures_section)));
+  }
+  AddSection("responses", cbor::Value(responses_));
+  return Encode(CreateTopLevel());
+}
+
+cbor::Value WebBundleBuilder::CreateEncodedSigned(
+    base::StringPiece validity_url,
+    base::StringPiece auth_sha256,
+    int64_t date,
+    int64_t expires,
+    base::StringPiece url,
+    base::StringPiece header_sha256,
+    base::StringPiece payload_integrity_header) {
+  cbor::Value::ArrayValue subset_hash_value;
+  subset_hash_value.emplace_back(CreateByteString(""));  // variants-value
+  subset_hash_value.emplace_back(CreateByteString(header_sha256));
+  subset_hash_value.emplace_back(payload_integrity_header);
+
+  cbor::Value::MapValue subset_hashes;
+  subset_hashes.emplace(url, std::move(subset_hash_value));
+
+  cbor::Value::MapValue signed_subset;
+  signed_subset.emplace("validity-url", validity_url);
+  signed_subset.emplace("auth-sha256", CreateByteString(auth_sha256));
+  signed_subset.emplace("date", date);
+  signed_subset.emplace("expires", expires);
+  signed_subset.emplace("subset-hashes", std::move(subset_hashes));
+  return cbor::Value(Encode(cbor::Value(signed_subset)));
+}
+
+cbor::Value WebBundleBuilder::CreateTopLevel() {
+  cbor::Value::ArrayValue toplevel_array;
+  toplevel_array.emplace_back(
+      CreateByteString(u8"\U0001F310\U0001F4E6"));  // "🌐📦"
+  toplevel_array.emplace_back(CreateByteString(base::StringPiece("b1\0\0", 4)));
+  toplevel_array.emplace_back(
+      cbor::Value::InvalidUTF8StringValueForTesting(fallback_url_));
+  toplevel_array.emplace_back(Encode(cbor::Value(section_lengths_)));
+  toplevel_array.emplace_back(sections_);
+  toplevel_array.emplace_back(CreateByteString(""));  // length (ignored)
+  return cbor::Value(toplevel_array);
+}
+
+std::vector<uint8_t> WebBundleBuilder::Encode(const cbor::Value& value) {
+  return *cbor::Writer::Write(value, writer_config_);
+}
+
+int64_t WebBundleBuilder::EncodedLength(const cbor::Value& value) {
+  return Encode(value).size();
+}
+
+}  // namespace test
+}  // namespace data_decoder
diff --git a/services/data_decoder/public/cpp/test_support/web_bundle_builder.h b/services/data_decoder/public/cpp/test_support/web_bundle_builder.h
new file mode 100644
index 0000000..71267ac
--- /dev/null
+++ b/services/data_decoder/public/cpp/test_support/web_bundle_builder.h
@@ -0,0 +1,80 @@
+// 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 SERVICES_DATA_DECODER_PUBLIC_CPP_TEST_SUPPORT_WEB_BUNDLE_BUILDER_H_
+#define SERVICES_DATA_DECODER_PUBLIC_CPP_TEST_SUPPORT_WEB_BUNDLE_BUILDER_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/strings/string_piece.h"
+#include "components/cbor/writer.h"
+
+namespace data_decoder {
+namespace test {
+
+// This class can be used to create a Web Bundle binary in tests.
+class WebBundleBuilder {
+ public:
+  using Headers = std::vector<std::pair<std::string, std::string>>;
+  struct ResponseLocation {
+    // /components/cbor uses int64_t for integer types.
+    int64_t offset;
+    int64_t length;
+  };
+
+  WebBundleBuilder(const std::string& fallback_url,
+                   const std::string& manifest_url);
+  ~WebBundleBuilder();
+
+  void AddExchange(base::StringPiece url,
+                   const Headers& response_headers,
+                   base::StringPiece payload);
+
+  ResponseLocation AddResponse(const Headers& headers,
+                               base::StringPiece payload);
+
+  void AddIndexEntry(base::StringPiece url,
+                     base::StringPiece variants_value,
+                     std::vector<ResponseLocation> response_locations);
+  void AddSection(base::StringPiece name, cbor::Value section);
+  void AddAuthority(cbor::Value::MapValue authority);
+  void AddVouchedSubset(cbor::Value::MapValue vouched_subset);
+
+  std::vector<uint8_t> CreateBundle();
+
+  // Creates a signed-subset structure with single subset-hashes entry,
+  // and returns it as a CBOR bytestring.
+  cbor::Value CreateEncodedSigned(base::StringPiece validity_url,
+                                  base::StringPiece auth_sha256,
+                                  int64_t date,
+                                  int64_t expires,
+                                  base::StringPiece url,
+                                  base::StringPiece header_sha256,
+                                  base::StringPiece payload_integrity_header);
+
+ private:
+  cbor::Value CreateTopLevel();
+  std::vector<uint8_t> Encode(const cbor::Value& value);
+
+  int64_t EncodedLength(const cbor::Value& value);
+
+  cbor::Writer::Config writer_config_;
+  std::string fallback_url_;
+  cbor::Value::ArrayValue section_lengths_;
+  cbor::Value::ArrayValue sections_;
+  cbor::Value::MapValue index_;
+  cbor::Value::ArrayValue responses_;
+  cbor::Value::ArrayValue authorities_;
+  cbor::Value::ArrayValue vouched_subsets_;
+
+  // 1 for the CBOR header byte. See the comment at the top of AddResponse().
+  int64_t current_responses_offset_ = 1;
+};
+
+}  // namespace test
+}  // namespace data_decoder
+
+#endif  // SERVICES_DATA_DECODER_PUBLIC_CPP_TEST_SUPPORT_WEB_BUNDLE_BUILDER_H_
diff --git a/services/data_decoder/web_bundle_parser_unittest.cc b/services/data_decoder/web_bundle_parser_unittest.cc
index f259dfe..eb637ba 100644
--- a/services/data_decoder/web_bundle_parser_unittest.cc
+++ b/services/data_decoder/web_bundle_parser_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/test/task_environment.h"
 #include "components/cbor/writer.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
+#include "services/data_decoder/public/cpp/test_support/web_bundle_builder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace data_decoder {
@@ -149,157 +150,6 @@
   return std::string(reinterpret_cast<const char*>(data.data()), data.size());
 }
 
-class BundleBuilder {
- public:
-  using Headers = std::vector<std::pair<std::string, std::string>>;
-  struct ResponseLocation {
-    // /components/cbor uses int64_t for integer types.
-    int64_t offset;
-    int64_t length;
-  };
-
-  BundleBuilder(const std::string& fallback_url,
-                const std::string& manifest_url)
-      : fallback_url_(fallback_url) {
-    writer_config_.allow_invalid_utf8_for_testing = true;
-    if (!manifest_url.empty()) {
-      AddSection("manifest",
-                 cbor::Value::InvalidUTF8StringValueForTesting(manifest_url));
-    }
-  }
-
-  void AddExchange(base::StringPiece url,
-                   const Headers& response_headers,
-                   base::StringPiece payload) {
-    AddIndexEntry(url, "", {AddResponse(response_headers, payload)});
-  }
-
-  ResponseLocation AddResponse(const Headers& headers,
-                               base::StringPiece payload) {
-    // We assume that the size of the CBOR header of the responses array is 1,
-    // which is true only if the responses array has no more than 23 elements.
-    EXPECT_LT(responses_.size(), 23u)
-        << "BundleBuilder cannot create bundles with more than 23 responses";
-
-    cbor::Value::ArrayValue response_array;
-    response_array.emplace_back(Encode(CreateHeaderMap(headers)));
-    response_array.emplace_back(CreateByteString(payload));
-    cbor::Value response(response_array);
-    int64_t response_length = EncodedLength(response);
-    ResponseLocation result = {current_responses_offset_, response_length};
-    current_responses_offset_ += response_length;
-    responses_.emplace_back(std::move(response));
-    return result;
-  }
-
-  void AddIndexEntry(base::StringPiece url,
-                     base::StringPiece variants_value,
-                     std::vector<ResponseLocation> response_locations) {
-    cbor::Value::ArrayValue index_value_array;
-    index_value_array.emplace_back(CreateByteString(variants_value));
-    for (const auto& location : response_locations) {
-      index_value_array.emplace_back(location.offset);
-      index_value_array.emplace_back(location.length);
-    }
-    index_.insert({cbor::Value::InvalidUTF8StringValueForTesting(url),
-                   cbor::Value(index_value_array)});
-  }
-
-  void AddSection(base::StringPiece name, cbor::Value section) {
-    section_lengths_.emplace_back(name);
-    section_lengths_.emplace_back(EncodedLength(section));
-    sections_.emplace_back(std::move(section));
-  }
-
-  void AddAuthority(cbor::Value::MapValue authority) {
-    authorities_.emplace_back(std::move(authority));
-  }
-
-  void AddVouchedSubset(cbor::Value::MapValue vouched_subset) {
-    vouched_subsets_.emplace_back(std::move(vouched_subset));
-  }
-
-  std::vector<uint8_t> CreateBundle() {
-    AddSection("index", cbor::Value(index_));
-    if (!authorities_.empty() || !vouched_subsets_.empty()) {
-      cbor::Value::ArrayValue signatures_section;
-      signatures_section.emplace_back(std::move(authorities_));
-      signatures_section.emplace_back(std::move(vouched_subsets_));
-      AddSection("signatures", cbor::Value(std::move(signatures_section)));
-    }
-    AddSection("responses", cbor::Value(responses_));
-    return Encode(CreateTopLevel());
-  }
-
-  // Creates a signed-subset structure with single subset-hashes entry,
-  // and returns it as a CBOR bytestring.
-  cbor::Value CreateEncodedSigned(base::StringPiece validity_url,
-                                  base::StringPiece auth_sha256,
-                                  int64_t date,
-                                  int64_t expires,
-                                  base::StringPiece url,
-                                  base::StringPiece header_sha256,
-                                  base::StringPiece payload_integrity_header) {
-    cbor::Value::ArrayValue subset_hash_value;
-    subset_hash_value.emplace_back(CreateByteString(""));  // variants-value
-    subset_hash_value.emplace_back(CreateByteString(header_sha256));
-    subset_hash_value.emplace_back(payload_integrity_header);
-
-    cbor::Value::MapValue subset_hashes;
-    subset_hashes.emplace(url, std::move(subset_hash_value));
-
-    cbor::Value::MapValue signed_subset;
-    signed_subset.emplace("validity-url", validity_url);
-    signed_subset.emplace("auth-sha256", CreateByteString(auth_sha256));
-    signed_subset.emplace("date", date);
-    signed_subset.emplace("expires", expires);
-    signed_subset.emplace("subset-hashes", std::move(subset_hashes));
-    return cbor::Value(Encode(cbor::Value(signed_subset)));
-  }
-
- private:
-  static cbor::Value CreateHeaderMap(const Headers& headers) {
-    cbor::Value::MapValue map;
-    for (const auto& pair : headers)
-      map.insert({CreateByteString(pair.first), CreateByteString(pair.second)});
-    return cbor::Value(std::move(map));
-  }
-
-  cbor::Value CreateTopLevel() {
-    cbor::Value::ArrayValue toplevel_array;
-    toplevel_array.emplace_back(
-        CreateByteString(u8"\U0001F310\U0001F4E6"));  // "🌐📦"
-    toplevel_array.emplace_back(
-        CreateByteString(base::StringPiece("b1\0\0", 4)));
-    toplevel_array.emplace_back(
-        cbor::Value::InvalidUTF8StringValueForTesting(fallback_url_));
-    toplevel_array.emplace_back(Encode(cbor::Value(section_lengths_)));
-    toplevel_array.emplace_back(sections_);
-    toplevel_array.emplace_back(CreateByteString(""));  // length (ignored)
-    return cbor::Value(toplevel_array);
-  }
-
-  std::vector<uint8_t> Encode(const cbor::Value& value) {
-    return *cbor::Writer::Write(value, writer_config_);
-  }
-
-  int64_t EncodedLength(const cbor::Value& value) {
-    return Encode(value).size();
-  }
-
-  cbor::Writer::Config writer_config_;
-  std::string fallback_url_;
-  cbor::Value::ArrayValue section_lengths_;
-  cbor::Value::ArrayValue sections_;
-  cbor::Value::MapValue index_;
-  cbor::Value::ArrayValue responses_;
-  cbor::Value::ArrayValue authorities_;
-  cbor::Value::ArrayValue vouched_subsets_;
-
-  // 1 for the CBOR header byte. See the comment at the top of AddResponse().
-  int64_t current_responses_offset_ = 1;
-};
-
 }  // namespace
 
 class WebBundleParserTest : public testing::Test {
@@ -308,7 +158,7 @@
 };
 
 TEST_F(WebBundleParserTest, WrongMagic) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   std::vector<uint8_t> bundle = builder.CreateBundle();
   bundle[3] ^= 1;
   TestDataSource data_source(bundle);
@@ -320,7 +170,7 @@
 }
 
 TEST_F(WebBundleParserTest, UnknownVersion) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   std::vector<uint8_t> bundle = builder.CreateBundle();
   // Modify the version string from "b1\0\0" to "q1\0\0".
   ASSERT_EQ(bundle[11], 'b');
@@ -334,7 +184,7 @@
 }
 
 TEST_F(WebBundleParserTest, FallbackURLIsNotUTF8) {
-  BundleBuilder builder("https://test.example.com/\xcc", kManifestUrl);
+  test::WebBundleBuilder builder("https://test.example.com/\xcc", kManifestUrl);
   std::vector<uint8_t> bundle = builder.CreateBundle();
   TestDataSource data_source(bundle);
 
@@ -345,7 +195,8 @@
 }
 
 TEST_F(WebBundleParserTest, FallbackURLHasFragment) {
-  BundleBuilder builder("https://test.example.com/#fragment", kManifestUrl);
+  test::WebBundleBuilder builder("https://test.example.com/#fragment",
+                                 kManifestUrl);
   std::vector<uint8_t> bundle = builder.CreateBundle();
   TestDataSource data_source(bundle);
 
@@ -356,7 +207,7 @@
 }
 
 TEST_F(WebBundleParserTest, SectionLengthsTooLarge) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   std::string too_long_section_name(8192, 'x');
   builder.AddSection(too_long_section_name, cbor::Value(0));
   TestDataSource data_source(builder.CreateBundle());
@@ -365,7 +216,7 @@
 }
 
 TEST_F(WebBundleParserTest, DuplicateSectionName) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddSection("foo", cbor::Value(0));
   builder.AddSection("foo", cbor::Value(0));
   TestDataSource data_source(builder.CreateBundle());
@@ -374,7 +225,7 @@
 }
 
 TEST_F(WebBundleParserTest, SingleEntry) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("https://test.example.com/",
                       {{":status", "200"}, {"content-type", "text/plain"}},
                       "payload");
@@ -394,7 +245,7 @@
 }
 
 TEST_F(WebBundleParserTest, InvalidRequestURL) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("", {{":status", "200"}, {"content-type", "text/plain"}},
                       "payload");
   TestDataSource data_source(builder.CreateBundle());
@@ -403,7 +254,7 @@
 }
 
 TEST_F(WebBundleParserTest, RequestURLIsNotUTF8) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("https://test.example.com/\xcc",
                       {{":status", "200"}, {"content-type", "text/plain"}},
                       "payload");
@@ -413,7 +264,7 @@
 }
 
 TEST_F(WebBundleParserTest, RequestURLHasBadScheme) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("file:///tmp/foo",
                       {{":status", "200"}, {"content-type", "text/plain"}},
                       "payload");
@@ -423,7 +274,7 @@
 }
 
 TEST_F(WebBundleParserTest, RequestURLHasCredentials) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("https://user:passwd@test.example.com/",
                       {{":status", "200"}, {"content-type", "text/plain"}},
                       "payload");
@@ -433,7 +284,7 @@
 }
 
 TEST_F(WebBundleParserTest, RequestURLHasFragment) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("https://test.example.com/#fragment",
                       {{":status", "200"}, {"content-type", "text/plain"}},
                       "payload");
@@ -443,7 +294,7 @@
 }
 
 TEST_F(WebBundleParserTest, NoStatusInResponseHeaders) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("https://test.example.com/",
                       {{"content-type", "text/plain"}},
                       "payload");  // ":status" is missing.
@@ -457,7 +308,7 @@
 }
 
 TEST_F(WebBundleParserTest, InvalidResponseStatus) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("https://test.example.com/",
                       {{":status", "0200"}, {"content-type", "text/plain"}},
                       "payload");
@@ -471,7 +322,7 @@
 }
 
 TEST_F(WebBundleParserTest, ExtraPseudoInResponseHeaders) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange(
       "https://test.example.com/",
       {{":status", "200"}, {":foo", ""}, {"content-type", "text/plain"}},
@@ -486,7 +337,7 @@
 }
 
 TEST_F(WebBundleParserTest, UpperCaseCharacterInHeaderName) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("https://test.example.com/",
                       {{":status", "200"}, {"Content-Type", "text/plain"}},
                       "payload");
@@ -500,7 +351,7 @@
 }
 
 TEST_F(WebBundleParserTest, InvalidHeaderValue) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("https://test.example.com/",
                       {{":status", "200"}, {"content-type", "\n"}}, "payload");
   TestDataSource data_source(builder.CreateBundle());
@@ -513,7 +364,7 @@
 }
 
 TEST_F(WebBundleParserTest, NoContentTypeWithNonEmptyContent) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("https://test.example.com/", {{":status", "200"}},
                       "payload");
   TestDataSource data_source(builder.CreateBundle());
@@ -526,7 +377,7 @@
 }
 
 TEST_F(WebBundleParserTest, NoContentTypeWithEmptyContent) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("https://test.example.com/", {{":status", "301"}}, "");
   TestDataSource data_source(builder.CreateBundle());
 
@@ -538,7 +389,7 @@
 }
 
 TEST_F(WebBundleParserTest, Variants) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   auto location1 = builder.AddResponse(
       {{":status", "200"}, {"content-type", "text/html"}}, "payload1");
   auto location2 = builder.AddResponse(
@@ -567,7 +418,7 @@
 }
 
 TEST_F(WebBundleParserTest, EmptyIndexEntry) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddIndexEntry("https://test.example.com/", "", {});
   TestDataSource data_source(builder.CreateBundle());
 
@@ -575,7 +426,7 @@
 }
 
 TEST_F(WebBundleParserTest, EmptyIndexEntryWithVariants) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddIndexEntry("https://test.example.com/",
                         "Accept;text/html;text/plain", {});
   TestDataSource data_source(builder.CreateBundle());
@@ -584,7 +435,7 @@
 }
 
 TEST_F(WebBundleParserTest, MultipleResponsesWithoutVariantsValue) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   auto location1 = builder.AddResponse(
       {{":status", "200"}, {"content-type", "text/html"}}, "payload1");
   auto location2 = builder.AddResponse(
@@ -597,7 +448,7 @@
 }
 
 TEST_F(WebBundleParserTest, AllKnownSectionInCritical) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("https://test.example.com/",
                       {{":status", "200"}, {"content-type", "text/plain"}},
                       "payload");
@@ -614,7 +465,7 @@
 }
 
 TEST_F(WebBundleParserTest, UnknownSectionInCritical) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("https://test.example.com/",
                       {{":status", "200"}, {"content-type", "text/plain"}},
                       "payload");
@@ -627,7 +478,7 @@
 }
 
 TEST_F(WebBundleParserTest, NoManifest) {
-  BundleBuilder builder(kFallbackUrl, std::string());
+  test::WebBundleBuilder builder(kFallbackUrl, std::string());
   builder.AddExchange("https://test.example.com/",
                       {{":status", "200"}, {"content-type", "text/plain"}},
                       "payload");
@@ -638,7 +489,7 @@
 }
 
 TEST_F(WebBundleParserTest, InvalidManifestURL) {
-  BundleBuilder builder(kFallbackUrl, "not-an-absolute-url");
+  test::WebBundleBuilder builder(kFallbackUrl, "not-an-absolute-url");
   builder.AddExchange("https://test.example.com/",
                       {{":status", "200"}, {"content-type", "text/plain"}},
                       "payload");
@@ -648,11 +499,12 @@
 }
 
 TEST_F(WebBundleParserTest, EmptySignaturesSection) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("https://test.example.com/",
                       {{":status", "200"}, {"content-type", "text/plain"}},
                       "payload");
-  // BundleBuilder omits signatures section if empty, so create it ourselves.
+  // test::WebBundleBuilder omits signatures section if empty, so create it
+  // ourselves.
   cbor::Value::ArrayValue signatures_section;
   signatures_section.emplace_back(cbor::Value::ArrayValue());  // authorities
   signatures_section.emplace_back(
@@ -667,7 +519,7 @@
 }
 
 TEST_F(WebBundleParserTest, SignaturesSection) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("https://test.example.com/",
                       {{":status", "200"}, {"content-type", "text/plain"}},
                       "payload");
@@ -726,7 +578,7 @@
 }
 
 TEST_F(WebBundleParserTest, MultipleSignatures) {
-  BundleBuilder builder(kFallbackUrl, kManifestUrl);
+  test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl);
   builder.AddExchange("https://test.example.com/",
                       {{":status", "200"}, {"content-type", "text/plain"}},
                       "payload");
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 21d5e7d1..85fb8f92 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -4145,6 +4145,52 @@
   }
 }
 
+// Test that the disable_secure_dns factory param is passed through to the
+// host resolver.
+TEST_F(NetworkContextTest, FactoryParams_DisableSecureDns) {
+  net::MockHostResolver resolver;
+  net::TestURLRequestContext url_request_context(
+      true /* delay_initialization */);
+  url_request_context.set_host_resolver(&resolver);
+  url_request_context.Init();
+
+  network_context_remote_.reset();
+  NetworkContext network_context(
+      network_service_.get(),
+      network_context_remote_.BindNewPipeAndPassReceiver(),
+      &url_request_context,
+      /*cors_exempt_header_list=*/std::vector<std::string>());
+
+  for (bool disable_secure_dns : {false, true}) {
+    mojo::Remote<mojom::URLLoaderFactory> loader_factory;
+    mojom::URLLoaderFactoryParamsPtr params =
+        mojom::URLLoaderFactoryParams::New();
+    params->process_id = mojom::kBrowserProcessId;
+    params->is_corb_enabled = false;
+    params->disable_secure_dns = disable_secure_dns;
+    network_context.CreateURLLoaderFactory(
+        loader_factory.BindNewPipeAndPassReceiver(), std::move(params));
+
+    ResourceRequest request;
+    request.url = GURL("http://example.test");
+    request.load_flags = net::LOAD_BYPASS_CACHE;
+    auto client = std::make_unique<TestURLLoaderClient>();
+    mojo::Remote<mojom::URLLoader> loader;
+    loader_factory->CreateLoaderAndStart(
+        loader.BindNewPipeAndPassReceiver(), 0 /* routing_id */,
+        0 /* request_id */, 0 /* options */, request, client->CreateRemote(),
+        net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
+
+    client->RunUntilComplete();
+    EXPECT_EQ(disable_secure_dns,
+              resolver.last_secure_dns_mode_override().has_value());
+    if (disable_secure_dns) {
+      EXPECT_EQ(net::DnsConfig::SecureDnsMode::OFF,
+                resolver.last_secure_dns_mode_override().value());
+    }
+  }
+}
+
 #if BUILDFLAG(IS_CT_SUPPORTED)
 TEST_F(NetworkContextTest, ExpectCT) {
   std::unique_ptr<NetworkContext> network_context =
diff --git a/services/network/public/cpp/server/http_server_unittest.cc b/services/network/public/cpp/server/http_server_unittest.cc
index 6ccde8fa..7b89fe184 100644
--- a/services/network/public/cpp/server/http_server_unittest.cc
+++ b/services/network/public/cpp/server/http_server_unittest.cc
@@ -188,7 +188,11 @@
     run_loop.Run();
     EXPECT_EQ(net::OK, net_error);
 
-    server_.reset(new HttpServer(std::move(server_socket_), this));
+    server_ = std::make_unique<HttpServer>(std::move(server_socket_), this);
+    // Wait for the HttpServer to start accepting connections. Since this is
+    // done in response to a request sent over a Mojo socket, it happens
+    // asynchronously.
+    base::RunLoop().RunUntilIdle();
   }
 
   void OnConnect(int connection_id) override {
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 3b7cee20..0b44874 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -589,6 +589,9 @@
   // Key used to isolate shared network resources like the cache.
   NetworkIsolationKey? network_isolation_key;
 
+  // Whether secure DNS should be disabled for requests.
+  bool disable_secure_dns = false;
+
   // True if this is for exclusive use by a trusted consumer. Only trusted
   // consumers can issue requests with ResourceRequest::trusted_params
   // populated.
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index d415ca3b..4298888d 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -420,7 +420,9 @@
         request.trusted_params->network_isolation_key);
   }
 
-  if (request.trusted_params) {
+  if (factory_params_->disable_secure_dns) {
+    url_request_->SetDisableSecureDns(true);
+  } else if (request.trusted_params) {
     url_request_->SetDisableSecureDns(
         request.trusted_params->disable_secure_dns);
   }
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 149013e..5650265 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -2906,7 +2906,8 @@
         "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android23.textpb"
+          "--avd-config=../../tools/android/avd/proto/generic_android23.textpb",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.gl_tests.filter"
         ],
         "merge": {
           "args": [
@@ -3544,7 +3545,8 @@
         "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android23.textpb"
+          "--avd-config=../../tools/android/avd/proto/generic_android23.textpb",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.media_unittests.filter"
         ],
         "merge": {
           "args": [
@@ -7086,7 +7088,8 @@
         "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb"
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.gl_tests.filter"
         ],
         "merge": {
           "args": [
@@ -7724,7 +7727,8 @@
         "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb"
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.media_unittests.filter"
         ],
         "merge": {
           "args": [
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 36a8a22..f92e681 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -25207,10 +25207,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "device_os": "MMB29Q",
-              "device_os_type": "userdebug",
-              "device_type": "bullhead",
-              "os": "Android"
+              "os": "Ubuntu-16.04"
             }
           ]
         },
@@ -37096,11 +37093,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "device_os": "PQ3A.190801.002",
-              "device_os_flavor": "google",
-              "device_os_type": "userdebug",
-              "device_type": "walleye",
-              "os": "Android"
+              "os": "Ubuntu-16.04"
             }
           ]
         },
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index 9e6a8ba6..f1ff72b 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -7677,10 +7677,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
+              "os": "Ubuntu-16.04"
             }
           ]
         },
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index 84462544..9f1eeb86 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -132,6 +132,12 @@
   ]
 }
 
+source_set("media_unittests_filters") {
+  data = [
+    "//testing/buildbot/filters/android.emulator.media_unittests.filter",
+  ]
+}
+
 source_set("ozone_unittests_filters") {
   data = [
     "//testing/buildbot/filters/chromeos.ozone_unittests.filter",
@@ -151,6 +157,7 @@
   testonly = true
 
   data = [
+    "//testing/buildbot/filters/android.emulator.gl_tests.filter",
     "//testing/buildbot/filters/android.pie_arm64_rel.gl_tests.filter",
   ]
 }
diff --git a/testing/buildbot/filters/android.emulator.gl_tests.filter b/testing/buildbot/filters/android.emulator.gl_tests.filter
new file mode 100644
index 0000000..315b3c9e
--- /dev/null
+++ b/testing/buildbot/filters/android.emulator.gl_tests.filter
@@ -0,0 +1,5 @@
+# https://crbug.com/1039873
+-WithWorkarounds/GLVirtualContextsTest.*
+-SetAggressivelyFreeResourcesTest.*
+-GLBGRAMipMapTest.*
+-GpuFenceTest.*
diff --git a/testing/buildbot/filters/android.emulator.media_unittests.filter b/testing/buildbot/filters/android.emulator.media_unittests.filter
new file mode 100644
index 0000000..1c01da1
--- /dev/null
+++ b/testing/buildbot/filters/android.emulator.media_unittests.filter
@@ -0,0 +1,4 @@
+# https://crbug.com/1039873
+-PaintCanvasVideoRendererWithGLTest.CopyVideoFrameTexturesToGLTextureI420
+-PaintCanvasVideoRendererWithGLTest.PaintI420
+-PaintCanvasVideoRendererWithGLTest.PaintI420NotSubset
diff --git a/testing/buildbot/filters/mac_window_server_killers.browser_tests.filter b/testing/buildbot/filters/mac_window_server_killers.browser_tests.filter
index cfcb56f..53de3f7 100644
--- a/testing/buildbot/filters/mac_window_server_killers.browser_tests.filter
+++ b/testing/buildbot/filters/mac_window_server_killers.browser_tests.filter
@@ -4,123 +4,6 @@
 -ConstrainedWebDialogBrowserTest.*
 -SSLClientCertificateSelectorMacTest.*
 
-# Investigation, round 2.
--All/PasswordManagerBrowserTestWithViewsFeature.*
--AllForms/FormStructureBrowserTest.*
--AppApiTest.*
--AppBackgroundPageApiTest.*
--AppBannerManagerBrowserTest.*
--AppWindowAPITest.*
--AppWindowApiTest.*
--AutocompleteBrowserTest.*
--AutofillRendererTest.*
--AutomationApiTest.*
--AutoplayPolicyTest.*
--BluetoothChooserBrowserTest.*
--BluetoothPrivateApiTest.*
--BookmarkAppNavigationThrottleCommonFormSubmissionBrowserTest.*
--BookmarkAppNavigationThrottleCommonLinkBrowserTest.*
--BookmarkAppNavigationThrottleExperimentalBrowserTest.*
--BookmarkAppNavigationThrottleExperimentalLinkBrowserTest.*
--BookmarkFolderAppleScriptTest.*
--BrowserActionApiTest.*
--BrowserActionsBarBrowserTest.*
--BrowserCloseManagerBrowserTest/BrowserCloseManagerBrowserTest.*
--BrowserNavigatorTest.*
--BrowserTabRestoreTest.*
--BrowserTest.*
--BrowserUiTest.*
--BrowsingDataRemoverBrowserTestP.*
--CDM_11/ECKEncryptedMediaTest.*
--CaptivePortalBlockingPageTest.*
--CaptivePortalBrowserTest.*
--CardUnmaskPromptViewBrowserTest.*
--ChromeLocatorTest.*
--ChromeSSLHostStateDelegateTest.*
--ChromeSitePerProcessTest.*
--CommandServiceTest.*
--ConnectionHelpTabHelperTest.*
--ConstrainedWebDialogBrowserTest.*
--ContentCapabilitiesTest.*
--ContentFaviconDriverTest.*
--ContentScriptApiTest.*
--ContentSettingBubbleDialogTest.*
--ContentSettingBubbleModelMixedScriptTest.*
--ContentSettingFramebustBlockBubbleModelTest.*
--ContentSettingsObserverBrowserTest.*
--ContextMenuBrowserTest.*
--ContinueWhereILeftOffTest.*
--CookieSettingsTest.*
--CrExtensionsA11yTest.*
--CrExtensionsA11yTestWithMultipleExensions.*
--CrExtensionsErrorConsoleA11yTest.*
--CrExtensionsItemsTest.*
--CrExtensionsShortcutA11yTestWithExtensions.*
--CrExtensionsShortcutA11yTestWithNoExtensions.*
--DNSErrorPageTest.*
--DeclarativeApiTest.*
--DeclarativeContentApiTest.*
--DeclarativeNetRequestBrowserTest.*
--DeclarativeNetRequestHostPermissionsBrowserTest.*
--DevToolsExtensionTest.*
--DevToolsManagerDelegateTest.*
--DevToolsSanityTest.*
--DeviceManagementServiceIntegrationTestInstance/DeviceManagementServiceIntegrationTest.*
--DiceBrowserTest.*
--DomDistillerViewerSourceBrowserTest.*
--DownloadDangerPromptBrowserTest.*
--DownloadExtensionTest.*
--DownloadInterruptReasonEnumsSynced.*
--DownloadTest.*
--EncodingAliases/BrowserEncodingTest.*
--ExecuteScriptApiTest.*
--ExecuteScriptApiTest/DestructiveScriptTest.*
--ExtensionApiTabTest.*
--ExtensionApiTest.*
--ExtensionBrowserTest.*
--ExtensionCrxInstallerTest.*
--ExtensionInstallDialogViewInteractiveBrowserTest.*
--ExtensionManagementApiTest.*
--ExtensionMessageBubbleBrowserTestMac.*
--ExtensionTabsTest.*
--ExtensionWebRequestApiTest.*
--ExtensionWebstorePrivateApiTest.*
--ExternalProtocolDialogBrowserTest.*
--FetchBehaviorTests/ContentVerifierHashTest.*
--FileSystemApiTest.*
--FindInPageControllerTest.*
--FlashEmbeds/ChromeContentRendererClientBrowserTest.*
--FlashPermissionBrowserTest.*
--FormAutocompleteTest.*
--FormAutofillTest.*
--FormClassifierTest.*
--FormControlClickDetectionTest.*
--FullscreenControllerTest.*
--GcmApiTest.*
--GeolocationBrowserTest.*
--GetAuthTokenFunctionTest.*
--HistoryBrowserTest.*
--HostedAppPWAOnlyTest.*
--HostedAppTest.*
--HttpsEngagementPageLoadMetricsBrowserTest.*
--IncognitoProfileMainNetworkContext/NetworkContextConfigurationBrowserTest.*
--InfoBarUiTest.*
--InlineLoginHelperBrowserTest.*
--InlineLoginUIBrowserTest.*
--InspectUITest.*
--InstallableManagerBrowserTest.*
--InstantThemeTest.*
--InterstitialUITest.*
--InterventionsInternalsUITest.*
--JavaScript/ExtensionBindingsApiTest.*
--JavaScriptBindings/ExternallyConnectableMessagingTest.*
--LocalNTPDoodleTest.*
--LocalNTPOneGoogleBarSmokeTest.*
--LocalNTPVoiceSearchSmokeTest.*
--LoginPromptBrowserTest.*
--MSE_ClearKey/EncryptedMediaTest.*
--MSE_ExternalClearKey/EncryptedMediaTest.*
-
 # Potential 10.13 killers.
 -DisableExtensionsExceptBrowserTest.*
 -ExtensionActionRunnerBrowserTest.*
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 2fe8623..98d4a16 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -244,8 +244,8 @@
       },
       'linux-trusty-rel': {
        'args': [
-	  '--test-launcher-filter-file=../../testing/buildbot/filters/linux_trusty_rel.browser_tests.filter',
-	  ]
+          '--test-launcher-filter-file=../../testing/buildbot/filters/linux_trusty_rel.browser_tests.filter',
+        ],
       },
       'mac-code-coverage': {
         # A subset of tests seem to cause WindowServer deaths on VMs.
@@ -698,11 +698,21 @@
         },
         'use_xvfb': False,
       },
+      'android-marshmallow-x86-fyi-rel': {
+        'args': [
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.gl_tests.filter',
+        ],
+      },
       'android-pie-arm64-rel': {
-	'args': [
+        'args': [
           '--test-launcher-filter-file=../../testing/buildbot/filters/android.pie_arm64_rel.gl_tests.filter', # https://crbug.com/1034007
         ],
       },
+      'android-pie-x86-fyi-rel': {
+        'args': [
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.gl_tests.filter',
+        ],
+      },
     },
   },
   'gl_unittests': {
@@ -895,11 +905,21 @@
   },
   'media_unittests': {
     'modifications': {
+      'android-marshmallow-x86-fyi-rel': {
+        'args': [
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.media_unittests.filter',
+        ],
+      },
       'android-pie-arm64-rel': {
         'args': [
           '--gtest_filter=-AAudio/AudioOutputTest.Play200HzTone/0', # https://crbug.com/1034009
         ],
       },
+      'android-pie-x86-fyi-rel': {
+        'args': [
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.media_unittests.filter',
+        ],
+      },
     },
   },
   'mojo_unittests': {
@@ -912,6 +932,45 @@
     },
   },
   'monochrome_apk_checker': {
+    'modifications': {
+      'ToTAndroid': {
+        'swarming': {
+          'dimension_sets': [
+            {
+              'device_os': None,
+              'device_playstore_version': None,
+              'device_type': None,
+              'os': 'Ubuntu-16.04',
+            },
+          ],
+        },
+      },
+      'android-arm64-proguard-rel': {
+        'swarming': {
+          'dimension_sets': [
+            {
+              'device_os': None,
+              'device_playstore_version': None,
+              'device_type': None,
+              'os': 'Ubuntu-16.04',
+            },
+          ],
+        },
+      },
+      'android-pie-arm64-rel': {
+        'swarming': {
+          'dimension_sets': [
+            {
+              'device_os': None,
+              'device_os_flavor': None,
+              'device_playstore_version': None,
+              'device_type': None,
+              'os': 'Ubuntu-16.04',
+            },
+          ],
+        },
+      },
+    },
     'remove_from': [
       # Don't run on trybots, which don't use proguard.
       # https://crbug.com/1029936.
diff --git a/testing/libfuzzer/fuzzers/mach/BUILD.gn b/testing/libfuzzer/fuzzers/mach/BUILD.gn
index 238cf115..151202d 100644
--- a/testing/libfuzzer/fuzzers/mach/BUILD.gn
+++ b/testing/libfuzzer/fuzzers/mach/BUILD.gn
@@ -5,6 +5,7 @@
 import("//third_party/protobuf/proto_library.gni")
 
 proto_library("proto") {
+  proto_in_dir = "//"
   sources = [
     "mach_message.proto",
   ]
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index b87b70c..0e185ce 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2020,6 +2020,24 @@
             ]
         }
     ],
+    "DesktopTabGroups": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "TabGroups"
+                    ]
+                }
+            ]
+        }
+    ],
     "DialMediaRouteProvider": [
         {
             "platforms": [
@@ -3687,6 +3705,32 @@
             ]
         }
     ],
+    "NTPZeroPrefixSuggestions": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "params": {
+                        "ZeroSuggestVariant:15:*": "RemoteNoUrl,Local",
+                        "ZeroSuggestVariant:1:*": "RemoteNoUrl,Local",
+                        "ZeroSuggestVariant:7:*": "RemoteNoUrl,Local"
+                    },
+                    "enable_features": [
+                        "NtpRealbox",
+                        "NtpRealboxMatchOmniboxTheme",
+                        "OmniboxOnFocusSuggestions",
+                        "OmniboxSuggestionTransparencyOptions"
+                    ]
+                }
+            ]
+        }
+    ],
     "NativeGellerizationRollout": [
         {
             "platforms": [
@@ -4094,22 +4138,6 @@
             ]
         }
     ],
-    "OmniboxGroupSuggestionsBySearchVsUrlAndroid": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "OmniboxGroupSuggestionsBySearchVsUrl",
-                        "OmniboxPreserveDefaultMatchScore"
-                    ]
-                }
-            ]
-        }
-    ],
     "OmniboxOnDeviceHeadSuggest": [
         {
             "platforms": [
@@ -5103,7 +5131,8 @@
                 {
                     "name": "Enabled",
                     "params": {
-                        "connection_options": "NSTP"
+                        "connection_options": "NSTP",
+                        "enable_quic": "true"
                     },
                     "enable_features": [
                         "QuicDoesNotUseFeatures"
diff --git a/third_party/blink/perf_tests/display_locking/fieldset_container_width_changes.html b/third_party/blink/perf_tests/display_locking/fieldset_container_width_changes.html
new file mode 100644
index 0000000..95f6f19
--- /dev/null
+++ b/third_party/blink/perf_tests/display_locking/fieldset_container_width_changes.html
@@ -0,0 +1,93 @@
+<!doctype HTML>
+
+<!--
+This test creates a fieldset with 10,000 non-trivial items. It locks the
+container and adjusts its width continuously. If render-subtree is properly
+optimized, then the width adjustments are very quick (< one frame). Otherwise,
+the layout recalculation leaks into the children element and the width
+adjustments are slow.
+-->
+
+<style>
+#container {
+  render-subtree: invisible skip-activation;
+
+  width: 500px;
+  height: 500px;
+  border: 1px solid black;
+  background: lightblue;
+  overflow: auto;
+}
+.item {
+  display: inline-block;
+  overflow: auto;
+  background: blue;
+  margin: 1px;
+  width: 10%;
+  height: 10%;
+}
+</style>
+
+<template id="item_template">
+<div class="item">
+  <div style="position: relative; width: 90%;">
+    relpos
+    <div style="position: absolute; top: 1px; left: 1%">
+      abspos
+    </div>
+  </div>
+  <div style="position: absolute; top: 150px; left: 1%">
+    abspos
+  </div>
+  lorem ipsum dolor sit amet
+</div>
+</template>
+
+<fieldset id=container><legend>legend</legend></fieldset>
+
+<script src="../resources/runner.js"></script>
+<script>
+function construct(n) {
+  const specimen = document.importNode(document.getElementById("item_template").content, true).firstElementChild;
+  const container = document.getElementById("container");
+  for (let i = 0; i < n; ++i) {
+    const clone = specimen.cloneNode(true);
+    container.appendChild(clone);
+  }
+}
+
+construct(10000);
+
+let widths = ["400px", "500px"];
+let width_index = 0;
+function changeStyle() {
+  document.getElementById("container").style.width = widths[width_index];
+  width_index = 1 - width_index;
+}
+
+let testDone = false;
+let startTime;
+function runTest() {
+  if (startTime) {
+    PerfTestRunner.measureValueAsync(PerfTestRunner.now() - startTime);
+    PerfTestRunner.addRunTestEndMarker();
+  }
+  if (testDone)
+    return;
+
+  startTime = PerfTestRunner.now();
+  PerfTestRunner.addRunTestEndMarker();
+
+  changeStyle();
+  requestAnimationFrame(runTest);
+}
+
+PerfTestRunner.startMeasureValuesAsync({
+  unit: 'ms',
+  done: () => { testDone = true; },
+  run: runTest,
+  warmUpCount: 3,
+  iterationCount: 5
+});
+
+</script>
diff --git a/third_party/blink/public/strings/blink_strings.grd b/third_party/blink/public/strings/blink_strings.grd
index 52452ca..48771af 100644
--- a/third_party/blink/public/strings/blink_strings.grd
+++ b/third_party/blink/public/strings/blink_strings.grd
@@ -964,6 +964,9 @@
       <message name="IDS_FORM_VALIDATION_RANGE_OVERFLOW_DATETIME" desc="Heading or short sentence shown when a form control value in a webpage needs to be earlier than or equal to a maximum date/time value specified by the page author, but a user specified a later date/time.">
         Value must be <ph name="MAXIMUM_DATE_OR_TIME">$1<ex>12/31/2013</ex></ph> or earlier.
       </message>
+      <message name="IDS_FORM_VALIDATION_RANGE_INVALID_DATETIME" desc="Heading or short sentence shown when a page author has specified minimum and maximum date/time values for a form control, but the maximum comes before the minimum.">
+        Minimum date (<ph name="MIN_DATE_OR_TIME">$1<ex>01/04/2013</ex></ph>) must come before Maximum date (<ph name="MAX_DATE_OR_TIME">$2<ex>02/04/2013</ex></ph>).
+      </message>
       <message name="IDS_FORM_VALIDATION_BAD_INPUT_DATETIME" desc="Heading or short sentence shown when a user specified an incomplete value or an invalid date (such as 02/31/2012) to a date/time form control in a webpage.">
         Please enter a valid value. The field is incomplete or has an invalid date.
       </message>
diff --git a/third_party/blink/public/strings/blink_strings_grd/IDS_FORM_VALIDATION_RANGE_INVALID_DATETIME.png.sha1 b/third_party/blink/public/strings/blink_strings_grd/IDS_FORM_VALIDATION_RANGE_INVALID_DATETIME.png.sha1
new file mode 100644
index 0000000..abb105b
--- /dev/null
+++ b/third_party/blink/public/strings/blink_strings_grd/IDS_FORM_VALIDATION_RANGE_INVALID_DATETIME.png.sha1
@@ -0,0 +1 @@
+b679d8c967a102fb942dc827969dc01cd14a75b5
\ No newline at end of file
diff --git a/third_party/blink/renderer/core/dom/document_init.cc b/third_party/blink/renderer/core/dom/document_init.cc
index 25a96b4..71bce92 100644
--- a/third_party/blink/renderer/core/dom/document_init.cc
+++ b/third_party/blink/renderer/core/dom/document_init.cc
@@ -30,6 +30,7 @@
 #include "third_party/blink/renderer/core/dom/document_init.h"
 
 #include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h"
 #include "third_party/blink/renderer/core/html/html_document.h"
@@ -285,8 +286,13 @@
 ContentSecurityPolicy* DocumentInit::GetContentSecurityPolicy() const {
   DCHECK(
       !(content_security_policy_ && content_security_policy_from_context_doc_));
-  if (context_document_ && content_security_policy_from_context_doc_)
-    return context_document_->GetContentSecurityPolicy();
+  if (context_document_ && content_security_policy_from_context_doc_) {
+    // Return a copy of the context documents' CSP. The return value will be
+    // modified, so this must be a copy.
+    ContentSecurityPolicy* csp = MakeGarbageCollected<ContentSecurityPolicy>();
+    csp->CopyStateFrom(context_document_->GetContentSecurityPolicy());
+    return csp;
+  }
   return content_security_policy_;
 }
 
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
index 22da7a8..850ea3a 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -1037,7 +1037,8 @@
   if (!delegate_ && !context_frame) {
     DCHECK(effective_type == DirectiveType::kChildSrc ||
            effective_type == DirectiveType::kFrameSrc ||
-           effective_type == DirectiveType::kPluginTypes);
+           effective_type == DirectiveType::kPluginTypes ||
+           effective_type == DirectiveType::kTrustedTypes);
     return;
   }
 
diff --git a/third_party/blink/renderer/core/html/forms/base_temporal_input_type.cc b/third_party/blink/renderer/core/html/forms/base_temporal_input_type.cc
index 4e007f8f..b4e3c3b4 100644
--- a/third_party/blink/renderer/core/html/forms/base_temporal_input_type.cc
+++ b/third_party/blink/renderer/core/html/forms/base_temporal_input_type.cc
@@ -104,6 +104,16 @@
                                  LocalizeValue(Serialize(minimum)));
 }
 
+String BaseTemporalInputType::RangeInvalidText(const Decimal& minimum,
+                                               const Decimal& maximum) const {
+  DCHECK(minimum > maximum)
+      << "RangeInvalidText should only be called with minimum>maximum";
+
+  return GetLocale().QueryString(IDS_FORM_VALIDATION_RANGE_INVALID_DATETIME,
+                                 LocalizeValue(Serialize(minimum)),
+                                 LocalizeValue(Serialize(maximum)));
+}
+
 Decimal BaseTemporalInputType::DefaultValueForStepUp() const {
   return Decimal::FromDouble(
       ConvertToLocalTime(base::Time::Now()).InMillisecondsF());
diff --git a/third_party/blink/renderer/core/html/forms/base_temporal_input_type.h b/third_party/blink/renderer/core/html/forms/base_temporal_input_type.h
index 13359fa..4d2aa088 100644
--- a/third_party/blink/renderer/core/html/forms/base_temporal_input_type.h
+++ b/third_party/blink/renderer/core/html/forms/base_temporal_input_type.h
@@ -96,6 +96,8 @@
   bool ValueMissing(const String&) const override;
   String RangeOverflowText(const Decimal& maximum) const override;
   String RangeUnderflowText(const Decimal& minimum) const override;
+  String RangeInvalidText(const Decimal& minimum,
+                          const Decimal& maximum) const override;
   Decimal DefaultValueForStepUp() const override;
   bool IsSteppable() const override;
   virtual String SerializeWithDate(const base::Optional<base::Time>&) const;
diff --git a/third_party/blink/renderer/core/html/forms/input_type.cc b/third_party/blink/renderer/core/html/forms/input_type.cc
index 987ba00..12d58a3f 100644
--- a/third_party/blink/renderer/core/html/forms/input_type.cc
+++ b/third_party/blink/renderer/core/html/forms/input_type.cc
@@ -389,6 +389,11 @@
   return String();
 }
 
+String InputType::RangeInvalidText(const Decimal&, const Decimal&) const {
+  NOTREACHED();
+  return String();
+}
+
 String InputType::TypeMismatchText() const {
   return GetLocale().QueryString(IDS_FORM_VALIDATION_TYPE_MISMATCH);
 }
@@ -444,6 +449,12 @@
 
   StepRange step_range(CreateStepRange(kRejectAny));
 
+  if (step_range.Minimum() > step_range.Maximum()) {
+    return std::make_pair(
+        RangeInvalidText(step_range.Minimum(), step_range.Maximum()),
+        g_empty_string);
+  }
+
   if (numeric_value < step_range.Minimum())
     return std::make_pair(RangeUnderflowText(step_range.Minimum()),
                           g_empty_string);
diff --git a/third_party/blink/renderer/core/html/forms/input_type.h b/third_party/blink/renderer/core/html/forms/input_type.h
index 9f36023a..cd90252 100644
--- a/third_party/blink/renderer/core/html/forms/input_type.h
+++ b/third_party/blink/renderer/core/html/forms/input_type.h
@@ -140,6 +140,8 @@
   virtual String BadInputText() const;
   virtual String RangeOverflowText(const Decimal& maximum) const;
   virtual String RangeUnderflowText(const Decimal& minimum) const;
+  virtual String RangeInvalidText(const Decimal& minimum,
+                                  const Decimal& maximum) const;
   virtual String TypeMismatchText() const;
   virtual String ValueMissingText() const;
   virtual bool CanSetStringValue() const;
diff --git a/third_party/blink/renderer/core/html/forms/resources/color_picker.css b/third_party/blink/renderer/core/html/forms/resources/color_picker.css
index 7ce1de1..ed9cc009 100644
--- a/third_party/blink/renderer/core/html/forms/resources/color_picker.css
+++ b/third_party/blink/renderer/core/html/forms/resources/color_picker.css
@@ -16,12 +16,12 @@
   background: #FFFFFF;
   display: flex;
   flex-direction: column;
-  height: 250px;
+  height: 304px;
   width: 232px;
 }
 
 visual-color-picker {
-  height: 71.5%;
+  height: 59%;
   min-height: 0;
 }
 
@@ -167,6 +167,31 @@
   width: 172px;
 }
 
+submission-controls {
+  align-items: center;
+  border-top: 1px solid #CECECE;
+  display: flex;
+  flex-direction: row;
+  height: 13%;
+  min-height: 0;
+}
+
+#submission-controls-padding {
+  height: 100%;
+  width: 84%;
+}
+
+submission-button {
+  padding: 3%;
+  text-align: center;
+  width: 8%;
+}
+
+submission-button:hover {
+  background-color: #F3F3F3;
+  border-radius: 2px;
+}
+
 @media (forced-colors: active) {
   color-viewer {
     forced-color-adjust: none;
diff --git a/third_party/blink/renderer/core/html/forms/resources/color_picker.js b/third_party/blink/renderer/core/html/forms/resources/color_picker.js
index e02931ec..a91dcc3 100644
--- a/third_party/blink/renderer/core/html/forms/resources/color_picker.js
+++ b/third_party/blink/renderer/core/html/forms/resources/color_picker.js
@@ -425,11 +425,14 @@
     super();
 
     this.selectedColor_ = initialColor;
-    this.colorWhenOpened_ = initialColor;
 
     this.visualColorPicker_ = new VisualColorPicker(initialColor);
     this.manualColorPicker_ = new ManualColorPicker(initialColor);
-    this.append(this.visualColorPicker_, this.manualColorPicker_);
+    this.submissionControls_ = new SubmissionControls(
+        this.onSubmitButtonClick_, this.onCancelButtonClick_);
+    this.append(
+        this.visualColorPicker_, this.manualColorPicker_,
+        this.submissionControls_);
 
     this.visualColorPicker_.addEventListener(
         'visual-color-picker-initialized', this.initializeListeners_);
@@ -477,9 +480,6 @@
       this.processingManualColorChange_ = true;
       this.visualColorPicker_.color = newColor;
       this.processingManualColorChange_ = false;
-
-      const selectedValue = newColor.asHex();
-      window.pagePopupController.setValue(selectedValue);
     }
   }
 
@@ -492,9 +492,6 @@
       if (!this.processingManualColorChange_) {
         this.selectedColor = newColor;
         this.manualColorPicker_.color = newColor;
-
-        const selectedValue = newColor.asHex();
-        window.pagePopupController.setValue(selectedValue);
       } else {
         // We are making a visual color change in response to a manual color
         // change. So we do not overwrite the manually specified values and do
@@ -509,16 +506,10 @@
   onKeyDown_ = (event) => {
     switch(event.key) {
       case 'Enter':
-        window.pagePopupController.closePopup();
+        this.submissionControls_.submitButton.click();
         break;
       case 'Escape':
-        if (this.selectedColor.equals(this.colorWhenOpened_)) {
-          window.pagePopupController.closePopup();
-        } else {
-          this.manualColorPicker_.dispatchEvent(new CustomEvent(
-              'manual-color-change',
-              {bubbles: true, detail: {color: this.colorWhenOpened_}}));
-        }
+        this.submissionControls_.cancelButton.click();
         break;
       case 'Tab':
         event.preventDefault();
@@ -548,6 +539,21 @@
         'color-value-container:not(.hidden-color-value-container) > input,' +
         '[tabindex]:not([tabindex=\'-1\'])'));
   }
+
+  static get COMMIT_DELAY_MS() {
+    return 100;
+  }
+
+  onSubmitButtonClick_ = () => {
+    const selectedValue = this.selectedColor_.asHex();
+    window.setTimeout(function() {
+      window.pagePopupController.setValueAndClosePopup(0, selectedValue);
+    }, ColorPicker.COMMIT_DELAY_MS);
+  };
+
+  onCancelButtonClick_ = () => {
+    window.pagePopupController.closePopup();
+  };
 }
 window.customElements.define('color-picker', ColorPicker);
 
@@ -1867,3 +1873,65 @@
   }
 }
 window.customElements.define('channel-label', ChannelLabel);
+
+/**
+ * SubmissionControls: Provides functionality to submit or discard a change.
+ */
+class SubmissionControls extends HTMLElement {
+  /**
+   * @param {function} submitCallback executed if the submit button is clicked
+   * @param {function} cancelCallback executed if the cancel button is clicked
+   */
+  constructor(submitCallback, cancelCallback) {
+    super();
+
+    const padding = document.createElement('span');
+    padding.setAttribute('id', 'submission-controls-padding');
+    this.append(padding);
+
+    this.submitButton_ = new SubmissionButton(
+        submitCallback,
+        '<svg width="14" height="10" viewBox="0 0 14 10" fill="none" ' +
+            'xmlns="http://www.w3.org/2000/svg"><path d="M13.3516 ' +
+            '1.35156L5 9.71094L0.648438 5.35156L1.35156 4.64844L5 ' +
+            '8.28906L12.6484 0.648438L13.3516 1.35156Z" fill="WindowText"/></svg>');
+    this.cancelButton_ = new SubmissionButton(
+        cancelCallback,
+        '<svg width="14" height="14" viewBox="0 0 14 14" fill="none" ' +
+            'xmlns="http://www.w3.org/2000/svg"><path d="M7.71094 7L13.1016 ' +
+            '12.3984L12.3984 13.1016L7 7.71094L1.60156 13.1016L0.898438 ' +
+            '12.3984L6.28906 7L0.898438 1.60156L1.60156 0.898438L7 ' +
+            '6.28906L12.3984 0.898438L13.1016 1.60156L7.71094 7Z" ' +
+            'fill="WindowText"/></svg>');
+    this.append(this.submitButton_, this.cancelButton_);
+  }
+
+  get submitButton() {
+    return this.submitButton_;
+  }
+
+  get cancelButton() {
+    return this.cancelButton_;
+  }
+}
+window.customElements.define('submission-controls', SubmissionControls);
+
+/**
+ * SubmissionButton: Button with a custom look that can be clicked for
+ *                   a submission action.
+ */
+class SubmissionButton extends HTMLElement {
+  /**
+   * @param {function} clickCallback executed when the button is clicked
+   * @param {string} htmlString custom look for the button
+   */
+  constructor(clickCallback, htmlString) {
+    super();
+
+    this.setAttribute('tabIndex', '0');
+    this.innerHTML = htmlString;
+
+    this.addEventListener('click', clickCallback);
+  }
+}
+window.customElements.define('submission-button', SubmissionButton);
diff --git a/third_party/blink/renderer/core/paint/box_model_object_painter.cc b/third_party/blink/renderer/core/paint/box_model_object_painter.cc
index 99a2f01..f6015ba 100644
--- a/third_party/blink/renderer/core/paint/box_model_object_painter.cc
+++ b/third_party/blink/renderer/core/paint/box_model_object_painter.cc
@@ -124,14 +124,24 @@
 BoxPainterBase::FillLayerInfo BoxModelObjectPainter::GetFillLayerInfo(
     const Color& color,
     const FillLayer& bg_layer,
-    BackgroundBleedAvoidance bleed_avoidance) const {
+    BackgroundBleedAvoidance bleed_avoidance,
+    bool is_painting_scrolling_background) const {
   return BoxPainterBase::FillLayerInfo(
       box_model_.GetDocument(), box_model_.StyleRef(),
       box_model_.HasOverflowClip(), color, bg_layer, bleed_avoidance,
       LayoutObject::ShouldRespectImageOrientation(&box_model_),
       (flow_box_ ? flow_box_->IncludeLogicalLeftEdge() : true),
       (flow_box_ ? flow_box_->IncludeLogicalRightEdge() : true),
-      box_model_.IsInline());
+      box_model_.IsInline(), is_painting_scrolling_background);
+}
+
+bool BoxModelObjectPainter::IsPaintingScrollingBackground(
+    const PaintInfo& paint_info) const {
+  if (!box_model_.IsBox())
+    return false;
+
+  const auto& this_box = ToLayoutBox(box_model_);
+  return BoxDecorationData::IsPaintingScrollingBackground(paint_info, this_box);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/box_model_object_painter.h b/third_party/blink/renderer/core/paint/box_model_object_painter.h
index eed39f2..03f1510 100644
--- a/third_party/blink/renderer/core/paint/box_model_object_painter.h
+++ b/third_party/blink/renderer/core/paint/box_model_object_painter.h
@@ -33,7 +33,9 @@
   BoxPainterBase::FillLayerInfo GetFillLayerInfo(
       const Color&,
       const FillLayer&,
-      BackgroundBleedAvoidance) const override;
+      BackgroundBleedAvoidance,
+      bool is_painting_scrolling_background) const override;
+  bool IsPaintingScrollingBackground(const PaintInfo&) const override;
 
   void PaintTextClipMask(GraphicsContext&,
                          const IntRect& mask_rect,
diff --git a/third_party/blink/renderer/core/paint/box_painter_base.cc b/third_party/blink/renderer/core/paint/box_painter_base.cc
index 3acd44b..4bdeb41 100644
--- a/third_party/blink/renderer/core/paint/box_painter_base.cc
+++ b/third_party/blink/renderer/core/paint/box_painter_base.cc
@@ -278,7 +278,8 @@
     RespectImageOrientationEnum respect_image_orientation,
     bool include_left,
     bool include_right,
-    bool is_inline)
+    bool is_inline,
+    bool is_painting_scrolling_background)
     : image(layer.GetImage()),
       color(bg_color),
       respect_image_orientation(respect_image_orientation),
@@ -318,7 +319,7 @@
   // BorderFillBox radius clipping is taken care of by
   // BackgroundBleedClip{Only,Layer}
   is_rounded_fill =
-      has_rounded_border &&
+      has_rounded_border && !is_painting_scrolling_background &&
       !(is_border_fill && BleedAvoidanceIsClipping(bleed_avoidance));
 
   should_paint_image = image && image->CanRender();
@@ -784,7 +785,9 @@
   if (rect.IsEmpty())
     return;
 
-  const FillLayerInfo info = GetFillLayerInfo(color, bg_layer, bleed_avoidance);
+  const FillLayerInfo info =
+      GetFillLayerInfo(color, bg_layer, bleed_avoidance,
+                       IsPaintingScrollingBackground(paint_info));
   // If we're not actually going to paint anything, abort early.
   if (!info.should_paint_image && !info.should_paint_color)
     return;
diff --git a/third_party/blink/renderer/core/paint/box_painter_base.h b/third_party/blink/renderer/core/paint/box_painter_base.h
index f5f1be3..a872080f 100644
--- a/third_party/blink/renderer/core/paint/box_painter_base.h
+++ b/third_party/blink/renderer/core/paint/box_painter_base.h
@@ -116,7 +116,8 @@
                   RespectImageOrientationEnum,
                   bool include_left_edge,
                   bool include_right_edge,
-                  bool is_inline);
+                  bool is_inline,
+                  bool is_painting_scrolling_background);
 
     // FillLayerInfo is a temporary, stack-allocated container which cannot
     // outlive the StyleImage.  This would normally be a raw pointer, if not for
@@ -155,9 +156,12 @@
   virtual PhysicalRect AdjustRectForScrolledContent(const PaintInfo&,
                                                     const FillLayerInfo&,
                                                     const PhysicalRect&) = 0;
-  virtual FillLayerInfo GetFillLayerInfo(const Color&,
-                                         const FillLayer&,
-                                         BackgroundBleedAvoidance) const = 0;
+  virtual FillLayerInfo GetFillLayerInfo(
+      const Color&,
+      const FillLayer&,
+      BackgroundBleedAvoidance,
+      bool is_painting_scrolling_background) const = 0;
+  virtual bool IsPaintingScrollingBackground(const PaintInfo&) const = 0;
   static void PaintInsetBoxShadow(const PaintInfo&,
                                   const FloatRoundedRect&,
                                   const ComputedStyle&,
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 83bf2ef..3c19540d 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
@@ -1320,7 +1320,7 @@
 }
 
 bool NGBoxFragmentPainter::IsPaintingScrollingBackground(
-    const PaintInfo& paint_info) {
+    const PaintInfo& paint_info) const {
   if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
     return paint_info.IsPaintingScrollingBackground();
 
@@ -1414,7 +1414,8 @@
 BoxPainterBase::FillLayerInfo NGBoxFragmentPainter::GetFillLayerInfo(
     const Color& color,
     const FillLayer& bg_layer,
-    BackgroundBleedAvoidance bleed_avoidance) const {
+    BackgroundBleedAvoidance bleed_avoidance,
+    bool is_painting_scrolling_background) const {
   const NGBorderEdges& border_edges = BorderEdges();
   const NGPhysicalBoxFragment& fragment = PhysicalFragment();
   return BoxPainterBase::FillLayerInfo(
@@ -1422,7 +1423,7 @@
       fragment.HasOverflowClip(), color, bg_layer, bleed_avoidance,
       LayoutObject::ShouldRespectImageOrientation(fragment.GetLayoutObject()),
       border_edges.line_left, border_edges.line_right,
-      fragment.GetLayoutObject()->IsInline());
+      fragment.GetLayoutObject()->IsInline(), is_painting_scrolling_background);
 }
 
 bool NGBoxFragmentPainter::IsInSelfHitTestingPhase(HitTestAction action) const {
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
index b558577..b60d84b 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
@@ -65,7 +65,9 @@
   BoxPainterBase::FillLayerInfo GetFillLayerInfo(
       const Color&,
       const FillLayer&,
-      BackgroundBleedAvoidance) const override;
+      BackgroundBleedAvoidance,
+      bool is_painting_scrolling_background) const override;
+  bool IsPaintingScrollingBackground(const PaintInfo&) const override;
 
   void PaintTextClipMask(GraphicsContext&,
                          const IntRect& mask_rect,
@@ -83,7 +85,6 @@
                        NGInlineCursor* descendants = nullptr);
 
   enum MoveTo { kDontSkipChildren, kSkipChildren };
-  bool IsPaintingScrollingBackground(const PaintInfo&);
   bool ShouldPaint(const ScopedPaintState&) const;
 
   void PaintBoxDecorationBackground(const PaintInfo&,
diff --git a/third_party/blink/renderer/core/xml/dom_parser.cc b/third_party/blink/renderer/core/xml/dom_parser.cc
index 996234e..4308d7e 100644
--- a/third_party/blink/renderer/core/xml/dom_parser.cc
+++ b/third_party/blink/renderer/core/xml/dom_parser.cc
@@ -46,7 +46,8 @@
       type,
       DocumentInit::Create()
           .WithContextDocument(context_document_)
-          .WithOwnerDocument(context_document_),
+          .WithOwnerDocument(context_document_)
+          .WithContentSecurityPolicyFromContextDoc(),
       false);
   doc->SetContent(str);
   doc->SetMimeType(AtomicString(type));
diff --git a/third_party/blink/renderer/platform/heap/member.h b/third_party/blink/renderer/platform/heap/member.h
index 27f2aee..7d30e18 100644
--- a/third_party/blink/renderer/platform/heap/member.h
+++ b/third_party/blink/renderer/platform/heap/member.h
@@ -113,21 +113,21 @@
   MemberBase(const MemberBase& other) : raw_(other) {
     SaveCreationThreadState();
     CheckPointer();
-    WriteBarrier();
+    // No write barrier for initializing stores.
   }
 
   template <typename U>
   MemberBase(const Persistent<U>& other) : raw_(other) {
     SaveCreationThreadState();
     CheckPointer();
-    WriteBarrier();
+    // No write barrier for initializing stores.
   }
 
   template <typename U>
   MemberBase(const MemberBase<U>& other) : raw_(other) {
     SaveCreationThreadState();
     CheckPointer();
-    WriteBarrier();
+    // No write barrier for initializing stores.
   }
 
   template <typename U>
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index a9c6d453..228496d 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -356,9 +356,6 @@
 crbug.com/1018273 [ Mac ] paint/invalidation/compositing/stop-painting-onto-scrolling-contents.html [ Failure ]
 crbug.com/1018273 [ Mac ] paint/overflow/composited-scroll-vertical-rl.html [ Failure ]
 
-crbug.com/1025019 compositing/overflow/scroller-with-border-radius.html [ Crash ]
-crbug.com/1025019 virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroller-with-border-radius.html [ Crash ]
-
 # Fail due to lack of fuzzy matching on Win and Mac platforms for WPT. The pixels in the pre-rotated reference
 # images do not exactly match the exif rotated images, probably due to jpeg decoding/encoding issues. Maybe
 # adjusting the image size to a multiple of 8 would fix this (so all jpeg blocks are solid color).
@@ -1778,9 +1775,15 @@
 
 # ====== Form Controls Refresh (chrome://flags/#form-controls-refresh) failures from here ======
 
+
 # ======
 # From this point until the end of the Form Controls Refresh section, these are
 # in-progress rebaselines, tracked at crbug.com/1035582.
+# ======
+
+# -
+# -
+# Group 1:
 crbug.com/1035582 fast/forms/basic-buttons.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/basic-inputs.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/button/button-align.html [ Failure Pass ]
@@ -1801,7 +1804,6 @@
 crbug.com/1035582 fast/forms/calendar-picker/calendar-picker-appearance-zoom200.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/calendar-picker/calendar-picker-datetimelocal.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/calendar-picker/calendar-picker-datetimelocal-with-step.html [ Failure Pass ]
-crbug.com/1035582 fast/forms/calendar-picker/calendar-picker-key-operations.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/calendar-picker/calendar-picker-should-not-change-datetimelocal-time.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/calendar-picker/calendar-picker-with-step.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/calendar-picker/datetimelocal-picker-choose-default-value-after-set-value.html [ Failure Pass ]
@@ -1842,6 +1844,12 @@
 crbug.com/1035582 fast/forms/input-appearance-height.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/input-button-sizes.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/input-value.html [ Failure Pass ]
+# -
+# -
+# -
+# -
+# -
+# Group 2
 crbug.com/1035582 fast/forms/month/month-appearance-basic.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/month/month-appearance-l10n.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/month-multiple-fields/month-multiple-fields-clearbutton-change-and-input-events.html [ Failure Pass ]
@@ -1881,14 +1889,12 @@
 crbug.com/1035582 fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl.html [ Failure Pass ]
-crbug.com/1035582 fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/suggestion-picker/datetimelocal-suggestion-picker-key-operations.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/suggestion-picker/month-suggestion-picker-appearance.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/suggestion-picker/month-suggestion-picker-appearance-rtl.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/suggestion-picker/month-suggestion-picker-key-operations.html [ Failure Pass Timeout ]
 crbug.com/1035582 fast/forms/suggestion-picker/time-suggestion-picker-appearance.html [ Failure Pass ]
-crbug.com/1035582 fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/suggestion-picker/time-suggestion-picker-key-operations.html [ Failure Pass ]
@@ -1914,14 +1920,12 @@
 crbug.com/1035582 fast/forms/week-multiple-fields/week-multiple-fields-spinbutton-change-and-input-events.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/week-multiple-fields/week-multiple-fields-wheel-event.html [ Failure Pass ]
 crbug.com/1035582 fast/forms/week/week-appearance-basic.html [ Failure Pass ]
-
-# These need test modification: the Color picker now pops up a dialog.
-crbug.com/1035582 external/wpt/css/selectors/focus-visible-003-manual.html [ Skip ]
-crbug.com/1035582 external/wpt/css/selectors/focus-visible-004-manual.html [ Skip ]
-
-# These fail only on Windows (and Linux; see a section further below):
-crbug.com/1035582 [ Win ] fast/forms/range/slider-mouse-events.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/forms/range/slider-zoomed.html [ Failure Pass ]
+# -
+# -
+# -
+# -
+# -
+# Group 3 (Win/Linux)
 crbug.com/1035582 [ Win ] fast/forms/select-popup/popup-menu-appearance-coarse.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/select-popup/popup-menu-appearance-empty.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/select-popup/popup-menu-appearance-fractional-width.html [ Failure Pass ]
@@ -1938,114 +1942,10 @@
 crbug.com/1035582 [ Win ] fast/forms/select-popup/popup-menu-appearance-zoom090.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/select-popup/popup-menu-appearance-zoom110.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/select-popup/popup-menu-appearance-zoom.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/hidpi/scrollbar-appearance-increase-device-scale-factor.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] paint/invalidation/forms/submit-focus-by-mouse-then-keydown.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/audio-service/http/tests/media/controls/toggle-class-with-state-source-buffer.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/cascade/fast/forms/select-popup/popup-menu-appearance-zoom090.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/cascade/fast/forms/select-popup/popup-menu-appearance-zoom110.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/layout_ng_flex_box/css3/flexbox/button.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/scalefactor150/fast/hidpi/static/popup-menu-appearance.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi.html [ Failure Pass ]
-# Below this line also fails on Mac.
-# See https://chromium-review.googlesource.com/c/chromium/src/+/1967608/22/third_party/blink/web_tests/TestExpectations
-# for a version of this file containing the Mac failures that occur when FormControlsRefresh
-# is enabled.
-crbug.com/1035582 [ Win ] virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/prefer_compositing_to_lcd_text/compositing/overflow/theme-affects-visual-overflow.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/prefer_compositing_to_lcd_text/compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/text-antialias/caps-lock-indicator-disabled.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/text-antialias/caps-lock-indicator-enabled.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/text-antialias/caps-lock-indicator-enabled-rtl.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/text-antialias/international/hindi-spacing.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/text-antialias/international/rtl-white-space-pre-wrap.html [ Failure Pass ]
-# Comment back in the Win7 version of this file on line 5905:
-crbug.com/1035582 [ Win ] virtual/text-antialias/international/unicode-bidi-plaintext-in-textarea.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/text-antialias/selection/mixed-directionality-selection.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/text-antialias/updateNewFont.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/fast/dom/HTMLMeterElement/meter-element.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/fast/dom/HTMLMeterElement/meter-element-repaint-on-update-value.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/fast/dom/HTMLMeterElement/meter-styles-changing-pseudo.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/fast/dom/HTMLProgressElement/progress-element.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/fast/parser/bad-xml-slash.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/fast/parser/entity-comment-in-textarea.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/fast/parser/open-comment-in-textarea.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/html/details_summary/details-no-summary4.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/html/details_summary/details-open2.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/html/details_summary/details-open4.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/html/details_summary/details-open-javascript.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/html/details_summary/details-replace-summary-child.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/html/details_summary/details-replace-text.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] compositing/overflow/theme-affects-visual-overflow.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] css1/box_properties/acid_test.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] css2.1/t09-c5526c-display-00-e.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/flexbox/button.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/html/css3-modsel-161.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/html/css3-modsel-23.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/html/css3-modsel-24.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/html/css3-modsel-25.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/html/css3-modsel-64.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/html/css3-modsel-68.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/html/css3-modsel-69.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/html/css3-modsel-70.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/xhtml/css3-modsel-161.xml [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/xhtml/css3-modsel-23.xml [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/xhtml/css3-modsel-24.xml [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/xhtml/css3-modsel-25.xml [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/xhtml/css3-modsel-64.xml [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/xhtml/css3-modsel-68.xml [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/xhtml/css3-modsel-69.xml [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/xhtml/css3-modsel-70.xml [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/xml/css3-modsel-161.xml [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/xml/css3-modsel-23.xml [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/xml/css3-modsel-24.xml [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/xml/css3-modsel-25.xml [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/xml/css3-modsel-64.xml [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/xml/css3-modsel-68.xml [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/xml/css3-modsel-69.xml [ Failure Pass ]
-crbug.com/1035582 [ Win ] css3/selectors3/xml/css3-modsel-70.xml [ Failure Pass ]
-crbug.com/1035582 [ Win ] editing/caret/caret-color-001.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] editing/caret/caret-color-002.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] editing/caret/caret-color-003.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] editing/caret/caret-color-004.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] editing/caret/caret-color-005.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] editing/caret/caret-color-007.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] editing/caret/caret-color-010.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] editing/caret/caret-color-012.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] editing/caret/caret-position.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] editing/input/caret-at-the-edge-of-input.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] editing/input/reveal-caret-of-multiline-input.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] editing/inserting/4960120-1.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] editing/pasteboard/4806874.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] editing/selection/4975120.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] editing/selection/selection-button-text.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] external/wpt/css/css-transforms/transform-input-015.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/block/basic/011.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/block/float/032.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/block/float/overhanging-tall-block.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/block/positioning/inline-block-relposition.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/css/input-search-padding.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/css/line-height.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/css/non-standard-checkbox-size.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/css/resize-corner-tracking.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/css/rtl-ordering.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/dom/HTMLMeterElement/meter-element.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/dom/HTMLMeterElement/meter-element-repaint-on-update-value.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/dom/HTMLMeterElement/meter-styles-changing-pseudo.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/dom/HTMLProgressElement/progress-element.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/dynamic/008.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/files/file-in-input-display.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/001.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/blankbuttons.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/button/button-cannot-be-nested.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/button/button-inner-block-reuse.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/forms/button/button-with-float.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/button-default-title.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/button-positioned.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/checkbox/checkbox-appearance-basic.html [ Failure Pass ]
@@ -2087,7 +1987,6 @@
 crbug.com/1035582 [ Win ] fast/forms/select/HTMLOptionElement_label07.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/select/listbox-appearance-separator.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/select/listbox-clip.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] fast/forms/select/listbox-overlay-scrollbar.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/select/listbox-scrollbar-incremental-load.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/select/listbox-width-change.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/select/listbox-with-display-none-option.html [ Failure Pass ]
@@ -2138,6 +2037,333 @@
 crbug.com/1035582 [ Win ] fast/forms/textarea/textarea-scroll-height.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/textarea/textarea-setinnerhtml.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/textarea/textarea-width.html [ Failure Pass ]
+
+crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-coarse.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-empty.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-fractional-width.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-long.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-many.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-minimum-font.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-rtl-default.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-rtl.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-single-option.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-styled.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-texttransform.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-transform.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-zoom090.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-zoom110.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-zoom.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/001.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/blankbuttons.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/button/button-cannot-be-nested.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/button/button-inner-block-reuse.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/button-default-title.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/button-positioned.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/checkbox/checkbox-appearance-basic.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/control-clip.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/control-clip-overflow.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/date/date-appearance-pseudo-elements.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/encoding-test.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/fieldset/fieldset-align.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/file/file-input-disabled.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/file/file-input-pressed-state.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/file/input-file-re-render.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/floating-textfield-relayout.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/formmove2.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/formmove3.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/formmove.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/huge-mac-input-clamped-height.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/huge-mac-input-clamped-width.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/indeterminate.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/input-align.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/input-first-letter.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/input-type-text-min-width.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/minWidthPercent.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/month/month-appearance-pseudo-elements.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/number/number-appearance-rtl.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/number/number-appearance-spinbutton-layer.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/plaintext-mode-2.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/radio/radio-appearance-basic.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/range/range-update.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/range/slider-thumb-shared-style.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/search/search-cancel-button-style-sharing.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/search/search-display-none-cancel-button.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/search/searchfield-heights.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/search/search-rtl.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/003.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/004.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/HTMLOptionElement_label01.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/HTMLOptionElement_label05.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/HTMLOptionElement_label06.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/HTMLOptionElement_label07.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/listbox-appearance-separator.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/listbox-clip.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/listbox-scrollbar-incremental-load.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/listbox-width-change.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/listbox-with-display-none-option.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/menulist-appearance-none.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/menulist-clip.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/menulist-deselect-update.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/menulist-narrow-width.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/menulist-no-overflow.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/menulist-option-wrap.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/menulist-restrict-line-height.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/menulist-separator-painting.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/menulist-style-color.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/menulist-width-change.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/multiselect-in-listbox-keyboard-focusring.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/optgroup-rendering.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/option-script.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/option-text-clip.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-autofilled.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-background-none.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-baseline.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-block-background.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-change-listbox-size.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-change-listbox-to-popup.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-change-popup-to-listbox.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-dirty-parent-pref-widths.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-empty-option-height.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-item-background-clip.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-listbox-multiple-no-focusring.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-list-box-with-height.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/selectlist-minsize.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-multiple-rtl.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-overflow-scroll.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-overflow-scroll-inherited.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-size-invalid.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-style.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/select/select-visual-hebrew.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/stuff-on-my-optgroup.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/tabbing-input-iframe.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/targeted-frame-submission.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/textarea/placeholder-appearance-textarea.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/textarea/reset-textarea.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-align.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-placeholder-visibility-1.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-placeholder-visibility-2.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-scrollbar.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-scrolled-focus-ring.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-scrolled-type.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-scroll-height.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-setinnerhtml.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-width.html [ Failure Pass ]
+# -
+# -
+# -
+# -
+# -
+# Group 4 (Win/Linux)
+crbug.com/1035582 [ Win ] fast/hidpi/scrollbar-appearance-increase-device-scale-factor.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] paint/invalidation/forms/submit-focus-by-mouse-then-keydown.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/audio-service/http/tests/media/controls/toggle-class-with-state-source-buffer.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/cascade/fast/forms/select-popup/popup-menu-appearance-zoom090.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/cascade/fast/forms/select-popup/popup-menu-appearance-zoom110.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/layout_ng_flex_box/css3/flexbox/button.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/scalefactor150/fast/hidpi/static/popup-menu-appearance.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/prefer_compositing_to_lcd_text/compositing/overflow/theme-affects-visual-overflow.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/prefer_compositing_to_lcd_text/compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/text-antialias/caps-lock-indicator-disabled.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/text-antialias/caps-lock-indicator-enabled.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/text-antialias/caps-lock-indicator-enabled-rtl.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/text-antialias/international/hindi-spacing.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/text-antialias/international/rtl-white-space-pre-wrap.html [ Failure Pass ]
+# Comment back in the Win7 version of this file on line 5905:
+crbug.com/1035582 [ Win ] virtual/text-antialias/international/unicode-bidi-plaintext-in-textarea.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/text-antialias/selection/mixed-directionality-selection.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/text-antialias/updateNewFont.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/fast/dom/HTMLMeterElement/meter-element.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/fast/dom/HTMLMeterElement/meter-element-repaint-on-update-value.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/fast/dom/HTMLMeterElement/meter-styles-changing-pseudo.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/fast/dom/HTMLProgressElement/progress-element.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/fast/parser/bad-xml-slash.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/fast/parser/entity-comment-in-textarea.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/fast/parser/open-comment-in-textarea.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/html/details_summary/details-no-summary4.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/html/details_summary/details-open2.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/html/details_summary/details-open4.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/html/details_summary/details-open-javascript.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/html/details_summary/details-replace-summary-child.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] virtual/web-components-v0-disabled/html/details_summary/details-replace-text.html [ Failure Pass ]
+
+crbug.com/1035582 [ Linux ] fast/hidpi/scrollbar-appearance-increase-device-scale-factor.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] paint/invalidation/forms/submit-focus-by-mouse-then-keydown.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/audio-service/http/tests/media/controls/toggle-class-with-state-source-buffer.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/cascade/fast/forms/select-popup/popup-menu-appearance-zoom090.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/cascade/fast/forms/select-popup/popup-menu-appearance-zoom110.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/layout_ng_flex_box/css3/flexbox/button.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/scalefactor150/fast/hidpi/static/popup-menu-appearance.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/prefer_compositing_to_lcd_text/compositing/overflow/theme-affects-visual-overflow.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/prefer_compositing_to_lcd_text/compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/text-antialias/caps-lock-indicator-disabled.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/text-antialias/caps-lock-indicator-enabled.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/text-antialias/caps-lock-indicator-enabled-rtl.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/text-antialias/international/hindi-spacing.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/text-antialias/international/rtl-white-space-pre-wrap.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/text-antialias/international/unicode-bidi-plaintext-in-textarea.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/text-antialias/selection/mixed-directionality-selection.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/text-antialias/updateNewFont.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/fast/dom/HTMLMeterElement/meter-element.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/fast/dom/HTMLMeterElement/meter-element-repaint-on-update-value.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/fast/dom/HTMLMeterElement/meter-styles-changing-pseudo.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/fast/dom/HTMLProgressElement/progress-element.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/fast/parser/bad-xml-slash.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/fast/parser/entity-comment-in-textarea.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/fast/parser/open-comment-in-textarea.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/html/details_summary/details-no-summary4.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/html/details_summary/details-open2.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/html/details_summary/details-open4.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/html/details_summary/details-open-javascript.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/html/details_summary/details-replace-summary-child.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/html/details_summary/details-replace-text.html [ Failure Pass ]
+# -
+# -
+# -
+# -
+# -
+# Group 5 (Win/Linux)
+crbug.com/1035582 [ Win ] compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] compositing/overflow/theme-affects-visual-overflow.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] css1/box_properties/acid_test.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] css2.1/t09-c5526c-display-00-e.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/flexbox/button.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/html/css3-modsel-161.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/html/css3-modsel-23.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/html/css3-modsel-24.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/html/css3-modsel-25.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/html/css3-modsel-64.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/html/css3-modsel-68.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/html/css3-modsel-69.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/html/css3-modsel-70.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/xhtml/css3-modsel-161.xml [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/xhtml/css3-modsel-23.xml [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/xhtml/css3-modsel-24.xml [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/xhtml/css3-modsel-25.xml [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/xhtml/css3-modsel-64.xml [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/xhtml/css3-modsel-68.xml [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/xhtml/css3-modsel-69.xml [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/xhtml/css3-modsel-70.xml [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/xml/css3-modsel-161.xml [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/xml/css3-modsel-23.xml [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/xml/css3-modsel-24.xml [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/xml/css3-modsel-25.xml [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/xml/css3-modsel-64.xml [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/xml/css3-modsel-68.xml [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/xml/css3-modsel-69.xml [ Failure Pass ]
+crbug.com/1035582 [ Win ] css3/selectors3/xml/css3-modsel-70.xml [ Failure Pass ]
+crbug.com/1035582 [ Win ] editing/caret/caret-color-001.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] editing/caret/caret-color-002.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] editing/caret/caret-color-003.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] editing/caret/caret-color-004.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] editing/caret/caret-color-005.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] editing/caret/caret-color-007.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] editing/caret/caret-color-010.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] editing/caret/caret-color-012.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] editing/caret/caret-position.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] editing/input/caret-at-the-edge-of-input.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] editing/input/reveal-caret-of-multiline-input.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] editing/inserting/4960120-1.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] editing/pasteboard/4806874.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] editing/selection/4975120.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] editing/selection/selection-button-text.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] fast/block/basic/011.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] fast/block/float/032.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] fast/block/float/overhanging-tall-block.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] fast/block/positioning/inline-block-relposition.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] fast/css/input-search-padding.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] fast/css/line-height.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] fast/css/non-standard-checkbox-size.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] fast/css/resize-corner-tracking.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] fast/css/rtl-ordering.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] fast/dom/HTMLMeterElement/meter-element.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] fast/dom/HTMLMeterElement/meter-element-repaint-on-update-value.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] fast/dom/HTMLMeterElement/meter-styles-changing-pseudo.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] fast/dom/HTMLProgressElement/progress-element.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] fast/dynamic/008.html [ Failure Pass ]
+crbug.com/1035582 [ Win ] fast/files/file-in-input-display.html [ Failure Pass ]
+
+crbug.com/1035582 [ Linux ] compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] compositing/overflow/theme-affects-visual-overflow.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css1/box_properties/acid_test.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css2.1/t09-c5526c-display-00-e.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/flexbox/button.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/html/css3-modsel-161.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/html/css3-modsel-23.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/html/css3-modsel-24.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/html/css3-modsel-25.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/html/css3-modsel-64.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/html/css3-modsel-68.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/html/css3-modsel-69.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/html/css3-modsel-70.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/xhtml/css3-modsel-161.xml [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/xhtml/css3-modsel-23.xml [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/xhtml/css3-modsel-24.xml [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/xhtml/css3-modsel-25.xml [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/xhtml/css3-modsel-64.xml [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/xhtml/css3-modsel-68.xml [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/xhtml/css3-modsel-69.xml [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/xhtml/css3-modsel-70.xml [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/xml/css3-modsel-161.xml [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/xml/css3-modsel-23.xml [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/xml/css3-modsel-24.xml [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/xml/css3-modsel-25.xml [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/xml/css3-modsel-64.xml [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/xml/css3-modsel-68.xml [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/xml/css3-modsel-69.xml [ Failure Pass ]
+crbug.com/1035582 [ Linux ] css3/selectors3/xml/css3-modsel-70.xml [ Failure Pass ]
+crbug.com/1035582 [ Linux ] editing/caret/caret-color-001.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] editing/caret/caret-color-002.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] editing/caret/caret-color-003.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] editing/caret/caret-color-004.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] editing/caret/caret-color-005.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] editing/caret/caret-color-007.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] editing/caret/caret-color-010.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] editing/caret/caret-color-012.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] editing/caret/caret-position.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] editing/input/caret-at-the-edge-of-input.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] editing/input/reveal-caret-of-multiline-input.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] editing/inserting/4960120-1.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] editing/pasteboard/4806874.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] editing/selection/4975120.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] editing/selection/selection-button-text.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/block/basic/011.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/block/float/032.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/block/float/overhanging-tall-block.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/block/positioning/inline-block-relposition.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/css/input-search-padding.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/css/line-height.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/css/non-standard-checkbox-size.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/css/resize-corner-tracking.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/css/rtl-ordering.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/dom/HTMLMeterElement/meter-element.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/dom/HTMLMeterElement/meter-element-repaint-on-update-value.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/dom/HTMLMeterElement/meter-styles-changing-pseudo.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/dom/HTMLProgressElement/progress-element.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/dynamic/008.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/files/file-in-input-display.html [ Failure Pass ]
+# -
+# -
+# -
+# -
+# -
+# Group 6 (Win/Linux)
 crbug.com/1035582 [ Win ] fast/forms/text/input-appearance-bkcolor.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/text/input-appearance-default-bkcolor.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/text/input-appearance-disabled.html [ Failure Pass ]
@@ -2181,6 +2407,56 @@
 crbug.com/1035582 [ Win ] fast/forms/validation-bubble-device-emulation.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/visual-hebrew-text-field.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/forms/week/week-appearance-pseudo-elements.html [ Failure Pass ]
+
+crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-bkcolor.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-default-bkcolor.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-disabled.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-focus.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-preventDefault.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-readonly.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-selection.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-visibility.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-width.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-baseline.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-double-click-selection-gap-bug.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-field-text-truncated.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-placeholder-visibility-1.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-placeholder-visibility-3.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-readonly-autoscroll.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-readonly-dimmed.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-readonly-empty.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-spaces.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-table.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-tab-shows-caret.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-text-click-inside.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-text-click-outside.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-text-double-click.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-text-drag-down.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-text-option-delete.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-text-scroll-left-on-blur.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-text-self-emptying-click.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-text-word-wrap.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/input-width.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text-style-color.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/textfield-focus-ring.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/textfield-overflow.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/text/text-font-height-mismatch.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/time/time-appearance-pseudo-elements.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/validation-bubble-appearance-edge.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/validation-bubble-appearance-escape.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/validation-bubble-appearance-iframe.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/validation-bubble-appearance-rtl-ui.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/validation-bubble-appearance-wrap.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/validation-bubble-device-emulation-change.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/validation-bubble-device-emulation.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/visual-hebrew-text-field.html [ Failure Pass ]
+crbug.com/1035582 [ Linux ] fast/forms/week/week-appearance-pseudo-elements.html [ Failure Pass ]
+# -
+# -
+# -
+# -
+# -
+# Group 7 (Win/Linux)
 crbug.com/1035582 [ Win ] fast/hidpi/resize-corner-hidpi.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/inline/positionedLifetime.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] fast/invalid/014.html [ Failure Pass ]
@@ -2297,265 +2573,7 @@
 crbug.com/1035582 [ Win ] virtual/layout_ng_block_frag/fast/multicol/multicol-with-child-renderLayer-for-input.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] virtual/layout_ng_block_frag/fragmentation/outline-crossing-columns.html [ Failure Pass ]
 crbug.com/1035582 [ Win ] external/wpt/css/css-pseudo/spelling-error-002-manual.html [ Failure Pass ]
-crbug.com/1035582 [ Win ] external/wpt/css/css-pseudo/spelling-error-003-manual.html [ Failure Pass ]
 
-# When testing locally on Linux, the list of failures seems to be identical to the one for Windows (see above):
-crbug.com/1035582 [ Linux ] fast/forms/range/slider-mouse-events.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/range/slider-zoomed.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-coarse.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-empty.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-fractional-width.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-long.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-many.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-minimum-font.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-rtl-default.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-rtl.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-single-option.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-styled.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-texttransform.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-transform.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-zoom090.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-zoom110.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select-popup/popup-menu-appearance-zoom.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/hidpi/scrollbar-appearance-increase-device-scale-factor.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] paint/invalidation/forms/submit-focus-by-mouse-then-keydown.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/audio-service/http/tests/media/controls/toggle-class-with-state-source-buffer.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/cascade/fast/forms/select-popup/popup-menu-appearance-zoom090.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/cascade/fast/forms/select-popup/popup-menu-appearance-zoom110.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/layout_ng_flex_box/css3/flexbox/button.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/scalefactor150/fast/hidpi/static/popup-menu-appearance.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/prefer_compositing_to_lcd_text/compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/prefer_compositing_to_lcd_text/compositing/overflow/theme-affects-visual-overflow.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/prefer_compositing_to_lcd_text/compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/text-antialias/caps-lock-indicator-disabled.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/text-antialias/caps-lock-indicator-enabled.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/text-antialias/caps-lock-indicator-enabled-rtl.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/text-antialias/international/hindi-spacing.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/text-antialias/international/rtl-white-space-pre-wrap.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/text-antialias/international/unicode-bidi-plaintext-in-textarea.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/text-antialias/selection/mixed-directionality-selection.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/text-antialias/updateNewFont.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/fast/dom/HTMLMeterElement/meter-element.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/fast/dom/HTMLMeterElement/meter-element-repaint-on-update-value.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/fast/dom/HTMLMeterElement/meter-styles-changing-pseudo.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/fast/dom/HTMLProgressElement/progress-element.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/fast/parser/bad-xml-slash.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/fast/parser/entity-comment-in-textarea.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/fast/parser/open-comment-in-textarea.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/html/details_summary/details-no-summary4.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/html/details_summary/details-open2.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/html/details_summary/details-open4.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/html/details_summary/details-open-javascript.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/html/details_summary/details-replace-summary-child.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] virtual/web-components-v0-disabled/html/details_summary/details-replace-text.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] compositing/overflow/theme-affects-visual-overflow.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css1/box_properties/acid_test.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css2.1/t09-c5526c-display-00-e.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/flexbox/button.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/html/css3-modsel-161.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/html/css3-modsel-23.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/html/css3-modsel-24.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/html/css3-modsel-25.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/html/css3-modsel-64.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/html/css3-modsel-68.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/html/css3-modsel-69.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/html/css3-modsel-70.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/xhtml/css3-modsel-161.xml [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/xhtml/css3-modsel-23.xml [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/xhtml/css3-modsel-24.xml [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/xhtml/css3-modsel-25.xml [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/xhtml/css3-modsel-64.xml [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/xhtml/css3-modsel-68.xml [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/xhtml/css3-modsel-69.xml [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/xhtml/css3-modsel-70.xml [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/xml/css3-modsel-161.xml [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/xml/css3-modsel-23.xml [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/xml/css3-modsel-24.xml [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/xml/css3-modsel-25.xml [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/xml/css3-modsel-64.xml [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/xml/css3-modsel-68.xml [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/xml/css3-modsel-69.xml [ Failure Pass ]
-crbug.com/1035582 [ Linux ] css3/selectors3/xml/css3-modsel-70.xml [ Failure Pass ]
-crbug.com/1035582 [ Linux ] editing/caret/caret-color-001.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] editing/caret/caret-color-002.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] editing/caret/caret-color-003.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] editing/caret/caret-color-004.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] editing/caret/caret-color-005.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] editing/caret/caret-color-007.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] editing/caret/caret-color-010.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] editing/caret/caret-color-012.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] editing/caret/caret-position.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] editing/input/caret-at-the-edge-of-input.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] editing/input/reveal-caret-of-multiline-input.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] editing/inserting/4960120-1.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] editing/pasteboard/4806874.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] editing/selection/4975120.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] editing/selection/selection-button-text.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] external/wpt/css/css-transforms/transform-input-015.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/block/basic/011.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/block/float/032.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/block/float/overhanging-tall-block.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/block/positioning/inline-block-relposition.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/css/input-search-padding.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/css/line-height.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/css/non-standard-checkbox-size.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/css/resize-corner-tracking.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/css/rtl-ordering.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/dom/HTMLMeterElement/meter-element.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/dom/HTMLMeterElement/meter-element-repaint-on-update-value.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/dom/HTMLMeterElement/meter-styles-changing-pseudo.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/dom/HTMLProgressElement/progress-element.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/dynamic/008.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/files/file-in-input-display.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/001.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/blankbuttons.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/button/button-cannot-be-nested.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/button/button-inner-block-reuse.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/button/button-with-float.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/button-default-title.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/button-positioned.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/checkbox/checkbox-appearance-basic.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/control-clip.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/control-clip-overflow.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/date/date-appearance-pseudo-elements.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/encoding-test.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/fieldset/fieldset-align.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/file/file-input-disabled.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/file/file-input-pressed-state.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/file/input-file-re-render.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/floating-textfield-relayout.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/formmove2.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/formmove3.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/formmove.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/huge-mac-input-clamped-height.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/huge-mac-input-clamped-width.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/indeterminate.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/input-align.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/input-first-letter.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/input-type-text-min-width.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/minWidthPercent.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/month/month-appearance-pseudo-elements.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/number/number-appearance-rtl.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/number/number-appearance-spinbutton-layer.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/plaintext-mode-2.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/radio/radio-appearance-basic.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/range/range-update.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/range/slider-thumb-shared-style.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/search/search-cancel-button-style-sharing.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/search/search-display-none-cancel-button.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/search/searchfield-heights.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/search/search-rtl.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/003.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/004.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/HTMLOptionElement_label01.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/HTMLOptionElement_label05.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/HTMLOptionElement_label06.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/HTMLOptionElement_label07.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/listbox-appearance-separator.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/listbox-clip.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/listbox-overlay-scrollbar.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/listbox-scrollbar-incremental-load.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/listbox-width-change.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/listbox-with-display-none-option.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/menulist-appearance-none.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/menulist-clip.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/menulist-deselect-update.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/menulist-narrow-width.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/menulist-no-overflow.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/menulist-option-wrap.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/menulist-restrict-line-height.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/menulist-separator-painting.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/menulist-style-color.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/menulist-width-change.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/multiselect-in-listbox-keyboard-focusring.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/optgroup-rendering.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/option-script.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/option-text-clip.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-autofilled.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-background-none.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-baseline.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-block-background.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-change-listbox-size.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-change-listbox-to-popup.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-change-popup-to-listbox.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-dirty-parent-pref-widths.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-empty-option-height.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-item-background-clip.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-listbox-multiple-no-focusring.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-list-box-with-height.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/selectlist-minsize.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-multiple-rtl.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-overflow-scroll.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-overflow-scroll-inherited.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-size-invalid.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-style.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/select/select-visual-hebrew.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/stuff-on-my-optgroup.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/tabbing-input-iframe.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/targeted-frame-submission.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/textarea/placeholder-appearance-textarea.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/textarea/reset-textarea.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-align.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-placeholder-visibility-1.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-placeholder-visibility-2.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-scrollbar.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-scrolled-focus-ring.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-scrolled-type.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-scroll-height.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-setinnerhtml.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/textarea/textarea-width.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-bkcolor.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-default-bkcolor.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-disabled.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-focus.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-preventDefault.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-readonly.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-selection.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-visibility.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-appearance-width.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-baseline.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-double-click-selection-gap-bug.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-field-text-truncated.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-placeholder-visibility-1.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-placeholder-visibility-3.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-readonly-autoscroll.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-readonly-dimmed.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-readonly-empty.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-spaces.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-table.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-tab-shows-caret.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-text-click-inside.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-text-click-outside.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-text-double-click.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-text-drag-down.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-text-option-delete.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-text-scroll-left-on-blur.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-text-self-emptying-click.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-text-word-wrap.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/input-width.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text-style-color.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/textfield-focus-ring.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/textfield-overflow.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/text/text-font-height-mismatch.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/time/time-appearance-pseudo-elements.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/validation-bubble-appearance-edge.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/validation-bubble-appearance-escape.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/validation-bubble-appearance-iframe.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/validation-bubble-appearance-rtl-ui.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/validation-bubble-appearance-wrap.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/validation-bubble-device-emulation-change.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/validation-bubble-device-emulation.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/visual-hebrew-text-field.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] fast/forms/week/week-appearance-pseudo-elements.html [ Failure Pass ]
 crbug.com/1035582 [ Linux ] fast/hidpi/resize-corner-hidpi.html [ Failure Pass ]
 crbug.com/1035582 [ Linux ] fast/inline/positionedLifetime.html [ Failure Pass ]
 crbug.com/1035582 [ Linux ] fast/invalid/014.html [ Failure Pass ]
@@ -2672,17 +2690,47 @@
 crbug.com/1035582 [ Linux ] virtual/layout_ng_block_frag/fast/multicol/multicol-with-child-renderLayer-for-input.html [ Failure Pass ]
 crbug.com/1035582 [ Linux ] virtual/layout_ng_block_frag/fragmentation/outline-crossing-columns.html [ Failure Pass ]
 crbug.com/1035582 [ Linux ] external/wpt/css/css-pseudo/spelling-error-002-manual.html [ Failure Pass ]
-crbug.com/1035582 [ Linux ] external/wpt/css/css-pseudo/spelling-error-003-manual.html [ Failure Pass ]
-
+# -
+# -
+# -
+# -
+# -
 # Problems rebaselining:
 crbug.com/1035582 virtual/cascade/fast/forms/date/date-appearance-basic.html [ Skip ]
 crbug.com/1035582 virtual/cascade/fast/forms/month/month-appearance-basic.html [ Skip ]
 crbug.com/1035582 wpt_internal/storage/estimate-usage-details-filesystem.https.tentative.any.html [ Skip ]
 
+# These need test modification: the Color picker now pops up a dialog.
+crbug.com/1035582 external/wpt/css/selectors/focus-visible-003-manual.html [ Skip ]
+crbug.com/1035582 external/wpt/css/selectors/focus-visible-004-manual.html [ Skip ]
+
 # I don't know why this one is failing:
 crbug.com/1035582 [ Win ] wpt_internal/storage/estimate-usage-details-filesystem.https.tentative.any-expected.txt [ Skip ]
 
-# End of rebaselines for crbug.com/1035582.
+# Failed in https://chromium-review.googlesource.com/c/chromium/src/+/1987072
+crbug.com/1035582 fast/forms/calendar-picker/calendar-picker-key-operations.html [ Skip ]
+# Comment back in at line 3002:
+crbug.com/1035582 [ Win ] fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew.html [ Skip ]
+crbug.com/1035582 [ Linux ] fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew.html [ Skip ]
+crbug.com/1035582 [ Win ] fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar.html [ Skip ]
+crbug.com/1035582 [ Linux ] fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar.html [ Skip ]
+
+# Failed in https://chromium-review.googlesource.com/c/chromium/src/+/1987075
+crbug.com/1035582 [ Win ] fast/forms/range/slider-mouse-events.html [ Skip ]
+crbug.com/1035582 [ Linux ] fast/forms/range/slider-mouse-events.html [ Skip ]
+crbug.com/1035582 [ Win ] fast/forms/range/slider-zoomed.html [ Skip ]
+crbug.com/1035582 [ Linux ] fast/forms/range/slider-zoomed.html [ Skip ]
+crbug.com/1035582 [ Win ] fast/forms/button/button-with-float.html [ Skip ]
+crbug.com/1035582 [ Win ] fast/forms/select/listbox-overlay-scrollbar.html [ Skip ]
+crbug.com/1035582 [ Linux ] fast/forms/button/button-with-float.html [ Skip ]
+crbug.com/1035582 [ Linux ] fast/forms/select/listbox-overlay-scrollbar.html [ Skip ]
+
+# Failed in https://chromium-review.googlesource.com/c/chromium/src/+/1986622
+crbug.com/1035582 external/wpt/css/css-pseudo/spelling-error-003-manual.html [ Skip ]
+crbug.com/1035582 external/wpt/css/css-transforms/transform-input-015.html [ Skip ]
+
+# ======
+# ====== End of rebaselines for crbug.com/1035582 ======
 # ======
 
 
diff --git a/third_party/blink/web_tests/animations/composition/bottom-composition.html b/third_party/blink/web_tests/animations/composition/bottom-composition.html
deleted file mode 100644
index 43d6fdf..0000000
--- a/third_party/blink/web_tests/animations/composition/bottom-composition.html
+++ /dev/null
@@ -1,71 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<body>
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-assertComposition({
-  property: 'bottom',
-  underlying: '50px',
-  addFrom: '100px',
-  addTo: '200px',
-}, [
-  {at: -0.3, is: '120px'},
-  {at: 0, is: '150px'},
-  {at: 0.5, is: '200px'},
-  {at: 1, is: '250px'},
-  {at: 1.5, is: '300px'},
-]);
-
-assertComposition({
-  property: 'bottom',
-  underlying: '100px',
-  addFrom: '10px',
-  addTo: '2px',
-}, [
-  {at: -0.5, is: '114px'},
-  {at: 0, is: '110px'},
-  {at: 0.5, is: '106px'},
-  {at: 1, is: '102px'},
-  {at: 1.5, is: '98px'},
-]);
-
-assertComposition({
-  property: 'bottom',
-  underlying: '10%',
-  addFrom: '100px',
-  addTo: '20%',
-}, [
-  {at: -0.3, is: 'calc(130px + 4%)'},
-  {at: 0, is: 'calc(100px + 10%)'},
-  {at: 0.5, is: 'calc(50px + 20%)'},
-  {at: 1, is: '30%'},
-  {at: 1.5, is: 'calc(-50px + 40%)'},
-]);
-
-assertComposition({
-  property: 'bottom',
-  underlying: '50px',
-  addFrom: '100px',
-  replaceTo: '200px',
-}, [
-  {at: -0.3, is: '135px'},
-  {at: 0, is: '150px'},
-  {at: 0.5, is: '175px'},
-  {at: 1, is: '200px'},
-  {at: 1.5, is: '225px'},
-]);
-
-assertComposition({
-  property: 'bottom',
-  underlying: '100px',
-  addFrom: '100px',
-  addTo: 'auto',
-}, [
-  {at: -0.3, is: '200px'},
-  {at: 0, is: '200px'},
-  {at: 0.5, is: 'auto'},
-  {at: 1, is: 'auto'},
-  {at: 1.5, is: 'auto'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/composition/clip-path-composition.html b/third_party/blink/web_tests/animations/composition/clip-path-composition.html
deleted file mode 100644
index 5b6b0f8..0000000
--- a/third_party/blink/web_tests/animations/composition/clip-path-composition.html
+++ /dev/null
@@ -1,182 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<body>
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-assertComposition({
-  property: 'clip-path',
-  underlying: 'circle(100px at 25px 25%)',
-  addFrom: 'circle(10px at 25px 75%)',
-  addTo: 'circle(50px at 50px center)',
-}, [
-  {at: -0.3, is: 'circle(98px at 42.5px 107.5%)'},
-  {at: 0, is: 'circle(110px at 50px 100%)'},
-  {at: 0.3, is: 'circle(122px at 57.5px 92.5%)'},
-  {at: 0.6, is: 'circle(134px at 65px 85%)'},
-  {at: 1, is: 'circle(150px at 75px 75%)'},
-  {at: 1.5, is: 'circle(170px at 87.5px 62.5%)'},
-]);
-
-assertComposition({
-  property: 'clip-path',
-  underlying: 'circle(100px at 20px 20%)',
-  addFrom: 'circle(50px at 50px 50%)',
-  replaceTo: 'circle(50% at 150px 150%)',
-}, [
-  {at: -0.3, is: 'circle(calc(195px + -15%) at 46px 46%)'},
-  {at: 0, is: 'circle(150px at 70px 70%)'},
-  {at: 0.3, is: 'circle(calc(105px + 15%) at 94px 94%)'},
-  {at: 0.6, is: 'circle(calc(60px + 30%) at 118px 118%)'},
-  {at: 1, is: 'circle(50% at 150px 150%)'},
-  {at: 1.5, is: 'circle(calc(-75px + 75%) at 190px 190%)'},
-]);
-
-assertComposition({
-  property: 'clip-path',
-  underlying: 'circle(farthest-side at 25px 75%)',
-  addFrom: 'circle(farthest-side at 25px 75%)',
-  addTo: 'circle(farthest-side at 50px center)',
-}, [
-  {at: 0.25, is: 'circle(farthest-side at 25px 75%)'},
-  {at: 0.75, is: 'circle(farthest-side at 50px 50%)'},
-]);
-
-assertComposition({
-  property: 'clip-path',
-  underlying: 'circle(50px at 10px 20px)',
-  addFrom: 'circle(50px at 10px 20px)',
-  addTo: 'circle(farthest-side at 30px 40px)',
-}, [
-  {at: 0.25, is: 'circle(100px at 20px 40px)'},
-  {at: 0.75, is: 'circle(farthest-side at 30px 40px)'},
-]);
-
-assertComposition({
-  property: 'clip-path',
-  underlying: 'ellipse(10px 20px at 30px 40px)',
-  addFrom: 'ellipse(40px 30px at 20px 10px)',
-  addTo: 'ellipse(140px 130px at 120px 110px)',
-}, [
-  {at: -0.3, is: 'ellipse(20px 20px at 20px 20px)'},
-  {at: 0, is: 'ellipse(50px 50px at 50px 50px)'},
-  {at: 0.3, is: 'ellipse(80px 80px at 80px 80px)'},
-  {at: 0.6, is: 'ellipse(110px 110px at 110px 110px)'},
-  {at: 1, is: 'ellipse(150px 150px at 150px 150px)'},
-  {at: 1.5, is: 'ellipse(200px 200px at 200px 200px)'},
-]);
-
-assertComposition({
-  property: 'clip-path',
-  underlying: 'ellipse(10px 20px at 30px 40px)',
-  replaceFrom: 'ellipse(40px 30px at 20px 10px)',
-  addTo: 'ellipse(40px 30px at 20px 10px)',
-}, [
-  {at: -0.3, is: 'ellipse(37px 24px at 11px -2px)'},
-  {at: 0, is: 'ellipse(40px 30px at 20px 10px)'},
-  {at: 0.3, is: 'ellipse(43px 36px at 29px 22px)'},
-  {at: 0.6, is: 'ellipse(46px 42px at 38px 34px)'},
-  {at: 1, is: 'ellipse(50px 50px at 50px 50px)'},
-  {at: 1.5, is: 'ellipse(55px 60px at 65px 70px)'},
-]);
-
-assertComposition({
-  property: 'clip-path',
-  underlying: 'ellipse(25px 75%)',
-  addFrom: 'ellipse()',
-  addTo: 'ellipse(closest-side farthest-side)',
-}, [
-  {at: 0.25, is: 'ellipse(at 50% 50%)'},
-  {at: 0.75, is: 'ellipse(closest-side farthest-side at 50% 50%)'},
-]);
-
-assertComposition({
-  property: 'clip-path',
-  underlying: 'inset(20px)',
-  addFrom: 'inset(20px)',
-  addTo: 'inset(40%)',
-}, [
-  {at: -0.3, is: 'inset(calc(46px + -12%))'},
-  {at: 0, is: 'inset(40px)'},
-  {at: 0.3, is: 'inset(calc(34px + 12%))'},
-  {at: 0.6, is: 'inset(calc(28px + 24%))'},
-  {at: 1, is: 'inset(calc(20px + 40%))'},
-  {at: 1.5, is: 'inset(calc(10px + 60%))'},
-]);
-
-assertComposition({
-  property: 'clip-path',
-  underlying: 'inset(1px 2px 3px 4px round 10px 20px 30px 40px / 50px 60px 70px 80px)',
-  addFrom: 'inset(1px 2px 3px 4px round 10px 20px 30px 40px / 50px 60px 70px 80px)',
-  replaceTo: 'inset(102px 104px 106px 108px round 120px 140px 160px 180px / 200px 220px 240px 260px)',
-}, [
-  {at: -0.3, is: 'inset(-28px -26px -24px -22px round 0px 10px 30px 50px / 70px 90px 110px 130px)'},
-  {at: 0, is: 'inset(2px 4px 6px 8px round 20px 40px 60px 80px / 100px 120px 140px 160px)'},
-  {at: 0.25, is: 'inset(27px 29px 31px 33px round 45px 65px 85px 105px / 125px 145px 165px 185px)'},
-  {at: 0.75, is: 'inset(77px 79px 81px 83px round 95px 115px 135px 155px / 175px 195px 215px 235px)'},
-  {at: 1, is: 'inset(102px 104px 106px 108px round 120px 140px 160px 180px / 200px 220px 240px 260px)'},
-  {at: 1.5, is: 'inset(152px 154px 156px 158px round 170px 190px 210px 230px / 250px 270px 290px 310px)'},
-]);
-
-assertComposition({
-  property: 'clip-path',
-  underlying: 'inset(1px 2px round 100px 200px)',
-  addFrom: 'inset(1px 2px round 100px 200px)',
-  addTo: 'inset(101px 102px 101px 102px)',
-}, [
-  {at: -0.3, is: 'inset(-28px -26px round 230px 460px)'},
-  {at: 0, is: 'inset(2px 4px round 200px 400px)'},
-  {at: 0.3, is: 'inset(32px 34px round 170px 340px)'},
-  {at: 0.6, is: 'inset(62px 64px round 140px 280px)'},
-  {at: 1, is: 'inset(102px 104px round 100px 200px)'},
-  {at: 1.5, is: 'inset(152px 154px round 50px 100px)'},
-]);
-
-assertComposition({
-  property: 'clip-path',
-  underlying: 'polygon(10px 20%, 30px 40%)',
-  addFrom: 'polygon(10px 20%, 30px 40%)',
-  addTo: 'polygon(110px 120%, 130px 140%)',
-}, [
-  {at: -0.3, is: 'polygon(-10px 10%, 30px 50%)'},
-  {at: 0, is: 'polygon(20px 40%, 60px 80%)'},
-  {at: 0.3, is: 'polygon(50px 70%, 90px 110%)'},
-  {at: 0.6, is: 'polygon(80px 100%, 120px 140%)'},
-  {at: 1, is: 'polygon(120px 140%, 160px 180%)'},
-  {at: 1.5, is: 'polygon(170px 190%, 210px 230%)'},
-]);
-
-assertComposition({
-  property: 'clip-path',
-  underlying: 'polygon(evenodd, 10px 20px)',
-  addFrom: 'polygon(evenodd, 10px 20px)',
-  addTo: 'polygon(evenodd, 110px 120px)',
-}, [
-  {at: -0.3, is: 'polygon(evenodd, -10px 10px)'},
-  {at: 0, is: 'polygon(evenodd, 20px 40px)'},
-  {at: 0.3, is: 'polygon(evenodd, 50px 70px)'},
-  {at: 0.6, is: 'polygon(evenodd, 80px 100px)'},
-  {at: 1, is: 'polygon(evenodd, 120px 140px)'},
-  {at: 1.5, is: 'polygon(evenodd, 170px 190px)'},
-]);
-
-assertComposition({
-  property: 'clip-path',
-  underlying: 'polygon(evenodd, 10px 20px)',
-  addFrom: 'polygon(evenodd, 10px 20px)',
-  addTo: 'polygon(nonzero, 30px 40px)',
-}, [
-  {at: 0.25, is: 'polygon(evenodd, 20px 40px)'},
-  {at: 0.75, is: 'polygon(30px 40px)'},
-]);
-
-assertComposition({
-  property: 'clip-path',
-  underlying: 'polygon(10px 20px, 30px 40px)',
-  addFrom: 'polygon(10px 20px, 30px 40px)',
-  addTo: 'polygon(30px 40px)',
-}, [
-  {at: 0.25, is: 'polygon(20px 40px, 60px 80px)'},
-  {at: 0.75, is: 'polygon(30px 40px)'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/composition/left-composition.html b/third_party/blink/web_tests/animations/composition/left-composition.html
deleted file mode 100644
index 87a8729..0000000
--- a/third_party/blink/web_tests/animations/composition/left-composition.html
+++ /dev/null
@@ -1,84 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<body>
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-assertComposition({
-  property: 'left',
-  underlying: '50px',
-  addFrom: '100px',
-  addTo: '200px',
-}, [
-  {at: -0.3, is: '120px'},
-  {at: 0, is: '150px'},
-  {at: 0.5, is: '200px'},
-  {at: 1, is: '250px'},
-  {at: 1.5, is: '300px'},
-]);
-
-assertComposition({
-  property: 'left',
-  underlying: '100px',
-  addFrom: '10px',
-  addTo: '2px',
-}, [
-  {at: -0.5, is: '114px'},
-  {at: 0, is: '110px'},
-  {at: 0.5, is: '106px'},
-  {at: 1, is: '102px'},
-  {at: 1.5, is: '98px'},
-]);
-
-assertComposition({
-  property: 'left',
-  underlying: '10%',
-  addFrom: '100px',
-  addTo: '20%',
-}, [
-  {at: -0.3, is: 'calc(130px + 4%)'},
-  {at: 0, is: 'calc(100px + 10%)'},
-  {at: 0.5, is: 'calc(50px + 20%)'},
-  {at: 1, is: '30%'},
-  {at: 1.5, is: 'calc(-50px + 40%)'},
-]);
-
-assertComposition({
-  property: 'left',
-  underlying: '10%',
-  addFrom: '100px',
-  addTo: '-10%',
-}, [
-  {at: -0.3, is: 'calc(130px + 13%)'},
-  {at: 0, is: 'calc(100px + 10%)'},
-  {at: 0.5, is: 'calc(50px + 5%)'},
-  {at: 1, is: '0%'},
-  {at: 1.5, is: 'calc(-50px - 5%)'},
-]);
-
-assertComposition({
-  property: 'left',
-  underlying: '50px',
-  addFrom: '100px',
-  replaceTo: '200px',
-}, [
-  {at: -0.3, is: '135px'},
-  {at: 0, is: '150px'},
-  {at: 0.5, is: '175px'},
-  {at: 1, is: '200px'},
-  {at: 1.5, is: '225px'},
-]);
-
-assertComposition({
-  property: 'left',
-  underlying: '100px',
-  addFrom: '100px',
-  addTo: 'auto',
-}, [
-  {at: -0.3, is: '200px'},
-  {at: 0, is: '200px'},
-  {at: 0.5, is: 'auto'},
-  {at: 1, is: 'auto'},
-  {at: 1.5, is: 'auto'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/composition/perspective-composition.html b/third_party/blink/web_tests/animations/composition/perspective-composition.html
deleted file mode 100644
index fbbb3c5e..0000000
--- a/third_party/blink/web_tests/animations/composition/perspective-composition.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<body>
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-assertComposition({
-  property: 'perspective',
-  underlying: '50px',
-  addFrom: '100px',
-  addTo: '200px',
-}, [
-  {at: -0.3, is: '120px'},
-  {at: 0, is: '150px'},
-  {at: 0.5, is: '200px'},
-  {at: 1, is: '250px'},
-  {at: 1.5, is: '300px'},
-]);
-
-assertComposition({
-  property: 'perspective',
-  underlying: '100px',
-  addFrom: '10px',
-  addTo: '2px',
-}, [
-  {at: -0.5, is: '114px'},
-  {at: 0, is: '110px'},
-  {at: 0.5, is: '106px'},
-  {at: 1, is: '102px'},
-  {at: 1.5, is: '98px'}, // Value clamping should happen after composition.
-]);
-
-assertComposition({
-  property: 'perspective',
-  underlying: '50px',
-  addFrom: '100px',
-  replaceTo: '200px',
-}, [
-  {at: -0.3, is: '135px'},
-  {at: 0, is: '150px'},
-  {at: 0.5, is: '175px'},
-  {at: 1, is: '200px'},
-  {at: 1.5, is: '225px'},
-]);
-
-assertComposition({
-  property: 'perspective',
-  underlying: '100px',
-  addFrom: '100px',
-  addTo: 'none',
-}, [
-  {at: -0.3, is: '200px'},
-  {at: 0, is: '200px'},
-  {at: 0.5, is: 'none'},
-  {at: 1, is: 'none'},
-  {at: 1.5, is: 'none'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/composition/right-composition.html b/third_party/blink/web_tests/animations/composition/right-composition.html
deleted file mode 100644
index 58ee2a68..0000000
--- a/third_party/blink/web_tests/animations/composition/right-composition.html
+++ /dev/null
@@ -1,71 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<body>
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-assertComposition({
-  property: 'right',
-  underlying: '50px',
-  addFrom: '100px',
-  addTo: '200px',
-}, [
-  {at: -0.3, is: '120px'},
-  {at: 0, is: '150px'},
-  {at: 0.5, is: '200px'},
-  {at: 1, is: '250px'},
-  {at: 1.5, is: '300px'},
-]);
-
-assertComposition({
-  property: 'right',
-  underlying: '100px',
-  addFrom: '10px',
-  addTo: '2px',
-}, [
-  {at: -0.5, is: '114px'},
-  {at: 0, is: '110px'},
-  {at: 0.5, is: '106px'},
-  {at: 1, is: '102px'},
-  {at: 1.5, is: '98px'},
-]);
-
-assertComposition({
-  property: 'right',
-  underlying: '10%',
-  addFrom: '100px',
-  addTo: '20%',
-}, [
-  {at: -0.3, is: 'calc(130px + 4%)'},
-  {at: 0, is: 'calc(100px + 10%)'},
-  {at: 0.5, is: 'calc(50px + 20%)'},
-  {at: 1, is: '30%'},
-  {at: 1.5, is: 'calc(-50px + 40%)'},
-]);
-
-assertComposition({
-  property: 'right',
-  underlying: '50px',
-  addFrom: '100px',
-  replaceTo: '200px',
-}, [
-  {at: -0.3, is: '135px'},
-  {at: 0, is: '150px'},
-  {at: 0.5, is: '175px'},
-  {at: 1, is: '200px'},
-  {at: 1.5, is: '225px'},
-]);
-
-assertComposition({
-  property: 'right',
-  underlying: '100px',
-  addFrom: '100px',
-  addTo: 'auto',
-}, [
-  {at: -0.3, is: '200px'},
-  {at: 0, is: '200px'},
-  {at: 0.5, is: 'auto'},
-  {at: 1, is: 'auto'},
-  {at: 1.5, is: 'auto'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/composition/rotate-composition.html b/third_party/blink/web_tests/animations/composition/rotate-composition.html
deleted file mode 100644
index acd5331c..0000000
--- a/third_party/blink/web_tests/animations/composition/rotate-composition.html
+++ /dev/null
@@ -1,158 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-assertComposition({
-  property: 'rotate',
-  underlying: '100deg',
-  addFrom: '10deg',
-  addTo: '30deg',
-}, [
-  {at: -1, is: '90deg'},
-  {at: 0, is: '110deg'},
-  {at: 0.25, is: '115deg'},
-  {at: 0.75, is: '125deg'},
-  {at: 1, is: '130deg'},
-  {at: 2, is: '150deg'},
-]);
-
-assertComposition({
-  property: 'rotate',
-  underlying: '1 0 0 200deg',
-  addFrom: '1 0 0 -100deg',
-  replaceTo: '1 0 0 40deg',
-}, [
-  {at: -1, is: '1 0 0 160deg'},
-  {at: 0, is: '1 0 0 100deg'},
-  {at: 0.25, is: '1 0 0 85deg'},
-  {at: 0.75, is: '1 0 0 55deg'},
-  {at: 1, is: '1 0 0 40deg'},
-  {at: 2, is: '1 0 0 -20deg'},
-]);
-
-assertComposition({
-  property: 'rotate',
-  underlying: '0 1 0 -40deg',
-  replaceFrom: '0 1 0 50deg',
-  addTo: '0 1 0 10deg',
-}, [
-  {at: -1, is: '0 1 0 130deg'},
-  {at: 0, is: '0 1 0 50deg'},
-  {at: 0.25, is: '0 1 0 30deg'},
-  {at: 0.75, is: '0 1 0 -10deg'},
-  {at: 1, is: '0 1 0 -30deg'},
-  {at: 2, is: '0 1 0 -110deg'},
-]);
-
-assertComposition({
-  property: 'rotate',
-  underlying: '1 2 3 40deg',
-  addFrom: '2 4 6 10deg',
-  addTo: '3 6 9 50deg',
-}, [
-  {at: -1, is: '1 2 3 10deg'},
-  {at: 0, is: '1 2 3 50deg'},
-  {at: 0.25, is: '1 2 3 60deg'},
-  {at: 0.75, is: '1 2 3 80deg'},
-  {at: 1, is: '1 2 3 90deg'},
-  {at: 2, is: '1 2 3 130deg'},
-]);
-
-assertComposition({
-  property: 'rotate',
-  underlying: '1 2 3 270deg',
-  addFrom: '1 2 3 90deg',
-  replaceTo: '0 1 0 100deg',
-}, [
-  {at: -1, is: '-5.49276e-17 -1 -1.64783e-16 100deg'},
-  {at: 0, is: '1 2 3 360deg'},
-  {at: 0.25, is: '-1.20172e-16 1 -3.60516e-16 25deg'},
-  {at: 0.75, is: '-1.51909e-17 1 -4.55726e-17 75deg'},
-  {at: 1, is: '0 1 0 100deg'},
-  {at: 2, is: '-3.3235e-17 -1 -9.97049e-17 160deg'},
-]);
-
-assertComposition({
-  property: 'rotate',
-  underlying: '1 2 3 90deg',
-  addFrom: '2 4 6 270deg',
-  replaceTo: '0 1 0 100deg',
-}, [
-  {at: -1, is: '-5.49276e-17 -1 -1.64783e-16 100deg'},
-  {at: 0, is: '1 2 3 360deg'},
-  {at: 0.25, is: '-1.20172e-16 1 -3.60516e-16 25deg'},
-  {at: 0.75, is: '-1.51909e-17 1 -4.55726e-17 75deg'},
-  {at: 1, is: '0 1 0 100deg'},
-  {at: 2, is: '-3.3235e-17 -1 -9.97049e-17 160deg'},
-]);
-
-assertComposition({
-  property: 'rotate',
-  underlying: '1 0 0 90deg',
-  addFrom: '0 1 0 180deg',
-  replaceTo: '0 0 1 90deg',
-}, [
-  {at: -1, is: '-6.12323e-17 -1 1.57009e-16 90deg'},
-  {at: 0, is: '-4.32978e-17 -0.707107 -0.707107 180deg'},
-  {at: 0.25, is: '-1.48952e-16 -0.894427 -0.447214 131.81deg'},
-  {at: 0.75, is: '-2.94392e-17 -0.707107 0.707107 70.5288deg'},
-  {at: 1, is: '90deg'},
-  {at: 2, is: '-6.12323e-17 -1 -4.71028e-16 90deg'},
-]);
-
-assertComposition({
-  property: 'rotate',
-  underlying: 'none',
-  addFrom: 'none',
-  replaceTo: '0 1 0 100deg',
-}, [
-  {at: -1, is: '0 1 0 -100deg'},
-  {at: 0, is: 'none'},
-  {at: 0.25, is: '0 1 0 25deg'},
-  {at: 0.75, is: '0 1 0 75deg'},
-  {at: 1, is: '0 1 0 100deg'},
-  {at: 2, is: '0 1 0 200deg'},
-]);
-
-assertComposition({
-  property: 'rotate',
-  underlying: 'none',
-  addFrom: '2 4 6 270deg',
-  replaceTo: 'none',
-}, [
-  {at: -1, is: '2 4 6 540deg'},
-  {at: 0, is: '2 4 6 270deg'},
-  {at: 0.25, is: '2 4 6 202.5deg'},
-  {at: 0.75, is: '2 4 6 67.5deg'},
-  {at: 1, is: 'none'},
-  {at: 2, is: '2 4 6 -270deg'},
-]);
-
-assertComposition({
-  property: 'rotate',
-  underlying: '1 2 3 90deg',
-  addFrom: 'none',
-  replaceTo: '0 1 0 100deg',
-}, [
-  {at: -1, is: '0.31 -0.22 0.92 131.66deg'},
-  {at: 0, is: '1 2 3 90deg'},
-  {at: 0.25, is: '0.21 0.73 0.64 86.72deg'},
-  {at: 0.75, is: '0.07 0.97 0.21 92.05deg'},
-  {at: 1, is: '0 1 0 100deg'},
-  {at: 2, is: '-0.2 0.79 -0.59 151.11deg'},
-]);
-
-assertComposition({
-  property: 'rotate',
-  underlying: '1 2 3 90deg',
-  addFrom: '2 4 6 270deg',
-  replaceTo: 'none',
-}, [
-  {at: -1, is: '1 2 3 720deg'},
-  {at: 0, is: '1 2 3 360deg'},
-  {at: 0.25, is: '1 2 3 270deg'},
-  {at: 0.75, is: '1 2 3 90deg'},
-  {at: 1, is: 'none'},
-  {at: 2, is: '1 2 3 -360deg'},
-]);
-</script>
diff --git a/third_party/blink/web_tests/animations/composition/scale-composition.html b/third_party/blink/web_tests/animations/composition/scale-composition.html
deleted file mode 100644
index c5e41633..0000000
--- a/third_party/blink/web_tests/animations/composition/scale-composition.html
+++ /dev/null
@@ -1,93 +0,0 @@
-<!DOCTYPE html>
-<body>
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-assertComposition({
-  property: 'scale',
-  underlying: '2 1',
-  addFrom: '3 1',
-  addTo: '4 1',
-}, [
-  {at: -0.5, is: '5 1'},
-  {at: 0, is: '6 1'},
-  {at: 0.25, is: '6.5 1'},
-  {at: 0.5, is: '7 1'},
-  {at: 0.75, is: '7.5 1'},
-  {at: 1, is: '8 1'},
-  {at: 1.5, is: '9 1'},
-]);
-
-assertComposition({
-  property: 'scale',
-  underlying: '1 2 3',
-  addFrom: '4 5 6',
-  replaceTo: '7 8 9',
-}, [
-  {at: -0.5, is: '2.5 11 22.5'},
-  {at: 0, is: '4 10 18'},
-  {at: 0.25, is: '4.75 9.5 15.75'},
-  {at: 0.5, is: '5.5 9 13.5'},
-  {at: 0.75, is: '6.25 8.5 11.25'},
-  {at: 1, is: '7 8 9'},
-  {at: 1.5, is: '8.5 7 4.5'},
-]);
-
-assertComposition({
-  property: 'scale',
-  underlying: 'none',
-  addFrom: 'none',
-  replaceTo: '1.5 1',
-}, [
-  {at: -1, is: '0.5 1'},
-  {at: 0, is: '1'},
-  {at: 0.25, is: '1.125 1'},
-  {at: 0.75, is: '1.375 1'},
-  {at: 1, is: '1.5 1'},
-  {at: 2, is: '2 1'},
-]);
-
-assertComposition({
-  property: 'scale',
-  underlying: 'none',
-  addFrom: '4 5 6',
-  replaceTo: 'none',
-}, [
-  {at: -1, is: '7 9 11'},
-  {at: 0, is: '4 5 6'},
-  {at: 0.25, is: '3.25 4 4.75'},
-  {at: 0.75, is: '1.75 2 2.25'},
-  {at: 1, is: 'none'},
-  {at: 2, is: '-2 -3 -4'},
-]);
-
-assertComposition({
-  property: 'scale',
-  underlying: '1 2 3',
-  addFrom: 'none',
-  replaceTo: '7 8 9',
-}, [
-  {at: -0.5, is: '-2 -1 0'},
-  {at: 0, is: '1 2 3'},
-  {at: 0.25, is: '2.5 3.5 4.5'},
-  {at: 0.5, is: '4 5 6'},
-  {at: 0.75, is: '5.5 6.5 7.5'},
-  {at: 1, is: '7 8 9'},
-  {at: 1.5, is: '10 11 12'},
-]);
-
-assertComposition({
-  property: 'scale',
-  underlying: '1 2 3',
-  addFrom: '4 5 6',
-  replaceTo: 'none',
-}, [
-  {at: -0.5, is: '5.5 14.5 26.5'},
-  {at: 0, is: '4 10 18'},
-  {at: 0.25, is: '3.25 7.75 13.75'},
-  {at: 0.5, is: '2.5 5.5 9.5'},
-  {at: 0.75, is: '1.75 3.25 5.25'},
-  {at: 1, is: 'none'},
-  {at: 1.5, is: '-0.5 -3.5 -7.5'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/composition/top-composition.html b/third_party/blink/web_tests/animations/composition/top-composition.html
deleted file mode 100644
index b3d898e..0000000
--- a/third_party/blink/web_tests/animations/composition/top-composition.html
+++ /dev/null
@@ -1,71 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<body>
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-assertComposition({
-  property: 'top',
-  underlying: '50px',
-  addFrom: '100px',
-  addTo: '200px',
-}, [
-  {at: -0.3, is: '120px'},
-  {at: 0, is: '150px'},
-  {at: 0.5, is: '200px'},
-  {at: 1, is: '250px'},
-  {at: 1.5, is: '300px'},
-]);
-
-assertComposition({
-  property: 'top',
-  underlying: '100px',
-  addFrom: '10px',
-  addTo: '2px',
-}, [
-  {at: -0.5, is: '114px'},
-  {at: 0, is: '110px'},
-  {at: 0.5, is: '106px'},
-  {at: 1, is: '102px'},
-  {at: 1.5, is: '98px'},
-]);
-
-assertComposition({
-  property: 'top',
-  underlying: '10%',
-  addFrom: '100px',
-  addTo: '20%',
-}, [
-  {at: -0.3, is: 'calc(130px + 4%)'},
-  {at: 0, is: 'calc(100px + 10%)'},
-  {at: 0.5, is: 'calc(50px + 20%)'},
-  {at: 1, is: '30%'},
-  {at: 1.5, is: 'calc(-50px + 40%)'},
-]);
-
-assertComposition({
-  property: 'top',
-  underlying: '50px',
-  addFrom: '100px',
-  replaceTo: '200px',
-}, [
-  {at: -0.3, is: '135px'},
-  {at: 0, is: '150px'},
-  {at: 0.5, is: '175px'},
-  {at: 1, is: '200px'},
-  {at: 1.5, is: '225px'},
-]);
-
-assertComposition({
-  property: 'top',
-  underlying: '100px',
-  addFrom: '100px',
-  addTo: 'auto',
-}, [
-  {at: -0.3, is: '200px'},
-  {at: 0, is: '200px'},
-  {at: 0.5, is: 'auto'},
-  {at: 1, is: 'auto'},
-  {at: 1.5, is: 'auto'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/composition/transform-composition.html b/third_party/blink/web_tests/animations/composition/transform-composition.html
deleted file mode 100644
index 1522cf0f3..0000000
--- a/third_party/blink/web_tests/animations/composition/transform-composition.html
+++ /dev/null
@@ -1,80 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<body>
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-// This file contains tests for the composition behavior of transforms that is
-// unrelated to the individual transform functions. For the transform functions
-// themselves, see the transform-*-composition.html subtests.
-
-// ------------------ Addition -----------------
-
-assertComposition({
-  property: 'transform',
-  underlying: 'rotateX(100deg) rotateY(100deg)',
-  addFrom: 'translate(10px, 20px)',
-  replaceTo: 'rotateX(200deg) rotateY(200deg) translate(110px, 220px)',
-}, [
-  {at: -0.5, is: 'rotateX(50deg) rotateY(50deg) translate(-40px, -80px)'},
-  {at: 0, is: 'rotateX(100deg) rotateY(100deg) translate(10px, 20px)'},
-  {at: 0.25, is: 'rotateX(125deg) rotateY(125deg) translate(35px, 70px)'},
-  {at: 0.5, is: 'rotateX(150deg) rotateY(150deg) translate(60px, 120px)'},
-  {at: 0.75, is: 'rotateX(175deg) rotateY(175deg) translate(85px, 170px)'},
-  {at: 1, is: 'rotateX(200deg) rotateY(200deg) translate(110px, 220px)'},
-  {at: 1.5, is: 'rotateX(250deg) rotateY(250deg) translate(160px, 320px)'},
-]);
-
-// Shorter list is extended with corresponding identity transforms for pairwise
-// interpolation.
-assertComposition({
-  property: 'transform',
-  underlying: 'rotateX(45deg)',
-  addFrom: 'none',
-  addTo: 'rotateY(360deg)',
-}, [
-  {at: -0.5, is: 'rotateX(45deg) rotateY(-180deg)'},
-  {at: 0, is: 'rotateX(45deg) rotateY(0deg)'},
-  {at: 0.25, is: 'rotateX(45deg) rotateY(90deg)'},
-  {at: 0.5, is: 'rotateX(45deg) rotateY(180deg)'},
-  {at: 0.75, is: 'rotateX(45deg) rotateY(270deg)'},
-  {at: 1, is: 'rotateX(45deg) rotateY(360deg)'},
-  {at: 1.5, is: 'rotateX(45deg) rotateY(540deg)'},
-]);
-
-// Matrix decomposition cases
-assertComposition({
-  property: 'transform',
-  underlying: 'rotateX(90deg)',
-  addFrom: 'translate(100px, 100px)',
-  addTo: 'scale(2)',
-}, [
-  {at: -0.5, is: 'matrix3d(0.5, 0, 0, 0, 0, 1.11022e-16, 0.5, 0, 0, -1, 2.22045e-16, 0, 150, 9.18485e-15, 150, 1)'},
-  {at: 0, is: 'matrix3d(1, 0, 0, 0, 0, 6.12323e-17, 1, 0, 0, -1, 6.12323e-17, 0, 100, 6.12323e-15, 100, 1)'},
-  {at: 0.25, is: 'matrix3d(1.25, 0, 0, 0, 0, 2.77556e-16, 1.25, 0, 0, -1, 2.22045e-16, 0, 75, 4.59243e-15, 75, 1)'},
-  {at: 0.5, is: 'matrix3d(1.5, 0, 0, 0, 0, 3.33067e-16, 1.5, 0, 0, -1, 2.22045e-16, 0, 50, 3.06162e-15, 50, 1)'},
-  {at: 0.75, is: 'matrix3d(1.75, 0, 0, 0, 0, 3.88578e-16, 1.75, 0, 0, -1, 2.22045e-16, 0, 25, 1.53081e-15, 25, 1)'},
-  {at: 1, is: 'matrix3d(2, 0, 0, 0, 0, 1.22465e-16, 2, 0, 0, -1, 6.12323e-17, 0, 0, 0, 0, 1)'},
-  {at: 1.5, is: 'matrix3d(2.5, 0, 0, 0, 0, 5.55112e-16, 2.5, 0, 0, -1, 2.22045e-16, 0, -50, -3.06162e-15, -50, 1)'},
-]);
-
-// Force a fallback to matrix interpolation.
-assertComposition({
-  property: 'transform',
-  underlying: 'rotateX(45deg)',
-  addFrom: 'scaleX(1)',
-  addTo: 'rotateY(360deg)',
-}, [
-  {at: -0.5, is: 'rotateX(45deg)'},
-  {at: 0, is: 'rotateX(45deg)'},
-  {at: 0.25, is: 'rotateX(45deg)'},
-  {at: 0.5, is: 'rotateX(45deg)'},
-  {at: 0.75, is: 'rotateX(45deg)'},
-  {at: 1, is: 'rotateX(45deg)'},
-  {at: 1.5, is: 'rotateX(45deg)'},
-]);
-
-// ------------------ Accumulation -----------------
-
-// TODO(smcgruer): Add tests for accumulation behaviors.
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/composition/transform-matrix-composition.html b/third_party/blink/web_tests/animations/composition/transform-matrix-composition.html
deleted file mode 100644
index 3ba6bdb..0000000
--- a/third_party/blink/web_tests/animations/composition/transform-matrix-composition.html
+++ /dev/null
@@ -1,201 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<body>
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-// For matrix and matrix3d, addition is defined as concatenation whilst
-// accumulation works by decomposing the matrix and then accumulating the
-// decomposed functions. We can therefore test the difference between the
-// two by mixing functions such that a naive multiplication would look
-// different than the accumulation behavior.
-//
-// Note that due to the complexities of decomposition the test space here is
-// huge; we cover some basic cases and hope that the tests for the individual
-// functions provide a lot of the remaining coverage.
-
-// Creates a matrix3d function, encoding the passed rotation and translation.
-// Note that the translate will not be affected by the rotation.
-function create3dMatrix(x, y, z, radians, translateX) {
-  // Normalize the rotation axes.
-  const length = Math.sqrt(x*x + y*y + z*z);
-  x /= length;
-  y /= length;
-  z /= length;
-
-  const sc = Math.sin(radians / 2) * Math.cos(radians / 2);
-  const sq = Math.sin(radians / 2) * Math.sin(radians / 2);
-
-  // https://drafts.csswg.org/css-transforms-2/#Rotate3dDefined
-  // https://drafts.csswg.org/css-transforms-2/#Translate3dDefined
-  return 'matrix3d(' + [
-      1 - 2 * (y*y + z*z) * sq,
-      2 * (x * y * sq + z * sc),
-      2 * (x * z * sq - y * sc),
-      0,
-      2 * (x * y * sq - z * sc),
-      1 - 2 * (x*x + z*z) * sq,
-      2 * (y * z * sq + x * sc),
-      0,
-      2 * (x * z * sq + y * sc),
-      2 * (y * z * sq - x * sc),
-      1 - 2 * (x*x + y*y) * sq,
-      0,
-      translateX, 0, 0, 1].join() + ')';
-}
-
-// ------------ Addition tests --------------
-
-assertComposition({
-  property: 'transform',
-  // translateX(100px) rotate(90deg)
-  underlying: 'matrix(0, 1, -1, 0, 100, 0)',
-  // translateX(100px)
-  addFrom: 'matrix(1, 0, 0, 1, 100, 0)',
-  // translateX(200px)
-  addTo: 'matrix(1, 0, 0, 1, 200, 0)',
-}, [
-  {at: -0.5, is: 'matrix(0, 1, -1, 0, 100, 50)'},
-  {at: 0, is: 'matrix(0, 1, -1, 0, 100, 100)'},
-  {at: 0.25, is: 'matrix(0, 1, -1, 0, 100, 125)'},
-  {at: 0.5, is: 'matrix(0, 1, -1, 0, 100, 150)'},
-  {at: 0.75, is: 'matrix(0, 1, -1, 0, 100, 175)'},
-  {at: 1, is: 'matrix(0, 1, -1, 0, 100, 200)'},
-  {at: 1.5, is: 'matrix(0, 1, -1, 0, 100, 250)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  // translateX(100px) rotate3d(1, 1, 0, 45deg)
-  underlying: create3dMatrix(1, 1, 0, Math.PI / 4, 100),
-  // translateX(100px)
-  addFrom: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 100, 0, 0, 1)',
-  // translateX(200px)
-  addTo: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 200, 0, 0, 1)',
-}, [
-  // matrix3ds are hard to read; these are the decomposed forms for clarity
-  {at: -0.5, is: 'translateX(100px) rotate3d(1, 1, 0, 45deg) translateX(50px)'},
-  {at: 0, is: 'translateX(100px) rotate3d(1, 1, 0, 45deg) translateX(100px)'},
-  {at: 0.25, is: 'translateX(100px) rotate3d(1, 1, 0, 45deg) translateX(125px)'},
-  {at: 0.5, is: 'translateX(100px) rotate3d(1, 1, 0, 45deg) translateX(150px)'},
-  {at: 0.75, is: 'translateX(100px) rotate3d(1, 1, 0, 45deg) translateX(175px)'},
-  {at: 1, is: 'translateX(100px) rotate3d(1, 1, 0, 45deg) translateX(200px)'},
-  {at: 1.5, is: 'translateX(100px) rotate3d(1, 1, 0, 45deg) translateX(250px)'},
-]);
-
-// Addition of non-invertible matrices is still defined as concatenation so
-// includes the underlying value.
-
-assertComposition({
-  property: 'transform',
-  // Non-invertible.
-  underlying: 'matrix(1, 1, 0, 0, 0, 100)',
-  // translateX(100px)
-  addFrom: 'matrix(1, 0, 0, 1, 100, 0)',
-  // translateX(200px)
-  addTo: 'matrix(1, 0, 0, 1, 200, 0)',
-}, [
-  {at: -0.5, is: 'matrix(1, 1, 0, 0, 100, 200)'},
-  {at: 0, is: 'matrix(1, 1, 0, 0, 100, 200)'},
-  {at: 0.25, is: 'matrix(1, 1, 0, 0, 100, 200)'},
-  {at: 0.5, is: 'matrix(1, 1, 0, 0, 200, 300)'},
-  {at: 0.75, is: 'matrix(1, 1, 0, 0, 200, 300)'},
-  {at: 1, is: 'matrix(1, 1, 0, 0, 200, 300)'},
-  {at: 1.5, is: 'matrix(1, 1, 0, 0, 200, 300)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  // translateX(100px)
-  underlying: 'matrix(1, 0, 0, 1, 100, 0)',
-  // Non-invertible
-  addFrom: 'matrix(1, 1, 0, 0, 0, 100)',
-  // translateX(200px)
-  addTo: 'matrix(1, 0, 0, 1, 200, 0)',
-}, [
-  {at: -0.5, is: 'matrix(1, 1, 0, 0, 100, 100)'},
-  {at: 0, is: 'matrix(1, 1, 0, 0, 100, 100)'},
-  {at: 0.25, is: 'matrix(1, 1, 0, 0, 100, 100)'},
-  {at: 0.5, is: 'matrix(1, 0, 0, 1, 300, 0)'},
-  {at: 0.75, is: 'matrix(1, 0, 0, 1, 300, 0)'},
-  {at: 1, is: 'matrix(1, 0, 0, 1, 300, 0)'},
-  {at: 1.5, is: 'matrix(1, 0, 0, 1, 300, 0)'},
-]);
-
-// ------------ Accumulation tests --------------
-
-assertComposition({
-  property: 'transform',
-  // translateX(100px) rotate(90deg)
-  underlying: 'matrix(0, 1, -1, 0, 100, 0)',
-  // translateX(100px)
-  accumulateFrom: 'matrix(1, 0, 0, 1, 100, 0)',
-  // translateX(200px)
-  accumulateTo: 'matrix(1, 0, 0, 1, 200, 0)',
-}, [
-  {at: -0.5, is: 'matrix(0, 1, -1, 0, 150, 0)'},
-  {at: 0, is: 'matrix(0, 1, -1, 0, 200, 0)'},
-  {at: 0.25, is: 'matrix(0, 1, -1, 0, 225, 0)'},
-  {at: 0.5, is: 'matrix(0, 1, -1, 0, 250, 0)'},
-  {at: 0.75, is: 'matrix(0, 1, -1, 0, 275, 0)'},
-  {at: 1, is: 'matrix(0, 1, -1, 0, 300, 0)'},
-  {at: 1.5, is: 'matrix(0, 1, -1, 0, 350, 0)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  // translateX(100px) rotate3d(1, 1, 0, 45deg)
-  underlying: create3dMatrix(1, 1, 0, Math.PI / 4, 100),
-  // translateX(100px)
-  accumulateFrom: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 100, 0, 0, 1)',
-  // translateX(200px)
-  accumulateTo: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 200, 0, 0, 1)',
-}, [
-  // matrix3ds are hard to read; these are the decomposed forms for clarity
-  {at: -0.5, is: 'translateX(150px) rotate3d(1, 1, 0, 45deg)'},
-  {at: 0, is: 'translateX(200px) rotate3d(1, 1, 0, 45deg)'},
-  {at: 0.25, is: 'translateX(225px) rotate3d(1, 1, 0, 45deg)'},
-  {at: 0.5, is: 'translateX(250px) rotate3d(1, 1, 0, 45deg)'},
-  {at: 0.75, is: 'translateX(275px) rotate3d(1, 1, 0, 45deg)'},
-  {at: 1, is: 'translateX(300px) rotate3d(1, 1, 0, 45deg)'},
-  {at: 1.5, is: 'translateX(350px) rotate3d(1, 1, 0, 45deg)'},
-]);
-
-// Accumulation of non-invertible matrices falls back to replace behavior.
-
-assertComposition({
-  property: 'transform',
-  // Non-invertible.
-  underlying: 'matrix(1, 1, 0, 0, 0, 100)',
-  // translateX(100px)
-  accumulateFrom: 'matrix(1, 0, 0, 1, 100, 0)',
-  // translateX(200px)
-  accumulateTo: 'matrix(1, 0, 0, 1, 200, 0)',
-}, [
-  {at: -0.5, is: 'matrix(1, 0, 0, 1, 50, 0)'},
-  {at: 0, is: 'matrix(1, 0, 0, 1, 100, 0)'},
-  {at: 0.25, is: 'matrix(1, 0, 0, 1, 125, 0)'},
-  {at: 0.5, is: 'matrix(1, 0, 0, 1, 150, 0)'},
-  {at: 0.75, is: 'matrix(1, 0, 0, 1, 175, 0)'},
-  {at: 1, is: 'matrix(1, 0, 0, 1, 200, 0)'},
-  {at: 1.5, is: 'matrix(1, 0, 0, 1, 250, 0)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  // translateX(100px)
-  underlying: 'matrix(1, 0, 0, 1, 100, 0)',
-  // Non-invertible
-  accumulateFrom: 'matrix(1, 1, 0, 0, 0, 100)',
-  // translateX(200px)
-  accumulateTo: 'matrix(1, 0, 0, 1, 200, 0)',
-}, [
-  {at: -0.5, is: 'matrix(1, 1, 0, 0, 0, 100)'},
-  {at: 0, is: 'matrix(1, 1, 0, 0, 0, 100)'},
-  {at: 0.25, is: 'matrix(1, 1, 0, 0, 0, 100)'},
-  {at: 0.5, is: 'matrix(1, 0, 0, 1, 300, 0)'},
-  {at: 0.75, is: 'matrix(1, 0, 0, 1, 300, 0)'},
-  {at: 1, is: 'matrix(1, 0, 0, 1, 300, 0)'},
-  {at: 1.5, is: 'matrix(1, 0, 0, 1, 300, 0)'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/composition/transform-perspective-composition.html b/third_party/blink/web_tests/animations/composition/transform-perspective-composition.html
deleted file mode 100644
index b385bf6..0000000
--- a/third_party/blink/web_tests/animations/composition/transform-perspective-composition.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<body>
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-// Addition and accumulation of perspective values are very similar, but not
-// identical. We can test the difference by constructing a scenario where a
-// perspective parameter would go negative in one case (and thus be clamped
-// to 0), and would not go negative in the other case.
-//
-// In the test below, the values differ at 1.5 progress. The reason for this
-// is that at 1.5 progress, the addition case (which uses concatenation)
-// computes to:
-//
-//   perspective(10px) perspective(-50px)
-//
-// Since perspective cannot go negative, this is clamped to:
-//
-//   perspective(10px) identity
-//
-// The accumulation case, on the other hand, combines the components
-// and so ends up blending from perspective(5px) to perspective(8.33...px) at
-// 1.5 progress, which results in perspective(12.5px) - this is what you would
-// get with addition too, if not for the clamping behavior.
-
-// ------------ Addition tests --------------
-
-assertComposition({
-  property: 'transform',
-  underlying: 'perspective(10px)',
-  addFrom: 'perspective(10px)',
-  addTo: 'perspective(50px)',
-}, [
-  {at: -0.5, is: 'perspective(4.12px)'},
-  {at: 0, is: 'perspective(5px)'},
-  {at: 0.25, is: 'perspective(5.45px)'},
-  {at: 0.5, is: 'perspective(6.15px)'},
-  {at: 0.75, is: 'perspective(7.06px)'},
-  {at: 1, is: 'perspective(8.33px)'},
-  {at: 1.5, is: 'perspective(10px)'},
-]);
-
-// ------------ Accumulation tests --------------
-
-assertComposition({
-  property: 'transform',
-  underlying: 'perspective(10px)',
-  accumulateFrom: 'perspective(10px)',
-  accumulateTo: 'perspective(50px)',
-}, [
-  {at: -0.5, is: 'perspective(4.12px)'},
-  {at: 0, is: 'perspective(5px)'},
-  {at: 0.25, is: 'perspective(5.45px)'},
-  {at: 0.5, is: 'perspective(6.15px)'},
-  {at: 0.75, is: 'perspective(7.06px)'},
-  {at: 1, is: 'perspective(8.33px)'},
-  {at: 1.5, is: 'perspective(12.5px)'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/composition/transform-rotate-composition.html b/third_party/blink/web_tests/animations/composition/transform-rotate-composition.html
deleted file mode 100644
index 09799fe..0000000
--- a/third_party/blink/web_tests/animations/composition/transform-rotate-composition.html
+++ /dev/null
@@ -1,157 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<body>
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-// ------------ Addition tests --------------
-
-assertComposition({
-  property: 'transform',
-  underlying: 'rotateX(20deg)',
-  addFrom: 'rotateX(40deg)',
-  addTo: 'rotateX(60deg)',
-}, [
-  {at: -0.5, is: 'rotateX(50deg)'},
-  {at: 0, is: 'rotateX(60deg)'},
-  {at: 0.25, is: 'rotateX(65deg)'},
-  {at: 0.5, is: 'rotateX(70deg)'},
-  {at: 0.75, is: 'rotateX(75deg)'},
-  {at: 1, is: 'rotateX(80deg)'},
-  {at: 1.5, is: 'rotateX(90deg)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  underlying: 'rotateY(20deg)',
-  addFrom: 'rotateY(40deg)',
-  addTo: 'rotateY(60deg)',
-}, [
-  {at: -0.5, is: 'rotateY(50deg)'},
-  {at: 0, is: 'rotateY(60deg)'},
-  {at: 0.25, is: 'rotateY(65deg)'},
-  {at: 0.5, is: 'rotateY(70deg)'},
-  {at: 0.75, is: 'rotateY(75deg)'},
-  {at: 1, is: 'rotateY(80deg)'},
-  {at: 1.5, is: 'rotateY(90deg)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  underlying: 'rotateZ(20deg)',
-  addFrom: 'rotateZ(40deg)',
-  addTo: 'rotateZ(60deg)',
-}, [
-  {at: -0.5, is: 'rotateZ(50deg)'},
-  {at: 0, is: 'rotateZ(60deg)'},
-  {at: 0.25, is: 'rotateZ(65deg)'},
-  {at: 0.5, is: 'rotateZ(70deg)'},
-  {at: 0.75, is: 'rotateZ(75deg)'},
-  {at: 1, is: 'rotateZ(80deg)'},
-  {at: 1.5, is: 'rotateZ(90deg)'},
-]);
-
-// When testing rotate functions in isolation, the additive and accumulation
-// behaviors are functionally identical. This test includes a skew to ensure
-// both methods are implemented; add should append the from/to after the skew.
-assertComposition({
-  property: 'transform',
-  underlying: 'rotate(45deg) skew(10deg, 20deg)',
-  addFrom: 'rotate(45deg)',
-  addTo: 'rotate(225deg)',
-}, [
-  {at: -0.5, is: 'rotate(45deg) skew(10deg, 20deg) rotate(-45deg)'},
-  {at: 0, is: 'rotate(45deg) skew(10deg, 20deg) rotate(45deg)'},
-  {at: 0.25, is: 'rotate(45deg) skew(10deg, 20deg) rotate(90deg)'},
-  {at: 0.5, is: 'rotate(45deg) skew(10deg, 20deg) rotate(135deg)'},
-  {at: 0.75, is: 'rotate(45deg) skew(10deg, 20deg) rotate(180deg)'},
-  {at: 1, is: 'rotate(45deg) skew(10deg, 20deg) rotate(225deg)'},
-  {at: 1.5, is: 'rotate(45deg) skew(10deg, 20deg) rotate(315deg)'},
-]);
-// ------------ Accumulation tests --------------
-
-assertComposition({
-  property: 'transform',
-  underlying: 'rotateX(20deg)',
-  accumulateFrom: 'rotateX(40deg)',
-  accumulateTo: 'rotateX(60deg)',
-}, [
-  {at: -0.5, is: 'rotateX(50deg)'},
-  {at: 0, is: 'rotateX(60deg)'},
-  {at: 0.25, is: 'rotateX(65deg)'},
-  {at: 0.5, is: 'rotateX(70deg)'},
-  {at: 0.75, is: 'rotateX(75deg)'},
-  {at: 1, is: 'rotateX(80deg)'},
-  {at: 1.5, is: 'rotateX(90deg)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  underlying: 'rotateY(20deg)',
-  accumulateFrom: 'rotateY(40deg)',
-  accumulateTo: 'rotateY(60deg)',
-}, [
-  {at: -0.5, is: 'rotateY(50deg)'},
-  {at: 0, is: 'rotateY(60deg)'},
-  {at: 0.25, is: 'rotateY(65deg)'},
-  {at: 0.5, is: 'rotateY(70deg)'},
-  {at: 0.75, is: 'rotateY(75deg)'},
-  {at: 1, is: 'rotateY(80deg)'},
-  {at: 1.5, is: 'rotateY(90deg)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  underlying: 'rotateZ(20deg)',
-  accumulateFrom: 'rotateZ(40deg)',
-  accumulateTo: 'rotateZ(60deg)',
-}, [
-  {at: -0.5, is: 'rotateZ(50deg)'},
-  {at: 0, is: 'rotateZ(60deg)'},
-  {at: 0.25, is: 'rotateZ(65deg)'},
-  {at: 0.5, is: 'rotateZ(70deg)'},
-  {at: 0.75, is: 'rotateZ(75deg)'},
-  {at: 1, is: 'rotateZ(80deg)'},
-  {at: 1.5, is: 'rotateZ(90deg)'},
-]);
-
-// The rotate functions all share the same primitive type (rotate3d), so can be
-// accumulated between. If primitive type matching is not properly being
-// performed, this test would likely fail with a fallback to replace behavior.
-assertComposition({
-  property: 'transform',
-  underlying: 'rotateX(45deg)',
-  accumulateFrom: 'rotateY(30deg)',
-  accumulateTo: 'rotateY(70deg)',
-}, [
-  // Due to how rotation is accumulated (addition of underlying angles), the
-  // behavior is identical to concatenating the components. The expectations
-  // are expressed as concatenations for readability.
-  {at: -0.5, is: 'rotateX(45deg) rotateY(10deg)'},
-  {at: 0, is: 'rotateX(45deg) rotateY(30deg)'},
-  {at: 0.25, is: 'rotateX(45deg) rotateY(40deg)'},
-  {at: 0.5, is: 'rotateX(45deg) rotateY(50deg)'},
-  {at: 0.75, is: 'rotateX(45deg) rotateY(60deg)'},
-  {at: 1, is: 'rotateX(45deg) rotateY(70deg)'},
-  {at: 1.5, is: 'rotateX(45deg) rotateY(90deg)'},
-]);
-
-// When testing rotate functions in isolation, the additive and accumulation
-// behaviors are functionally identical. This test includes a skew to ensure
-// both methods are implemented; accumulate should combine the rotate before
-// the skew.
-assertComposition({
-  property: 'transform',
-  underlying: 'rotate(45deg) skew(10deg, 20deg)',
-  accumulateFrom: 'rotate(45deg)',
-  accumulateTo: 'rotate(225deg)',
-}, [
-  {at: -0.5, is: 'rotate(0deg) skew(10deg, 20deg)'},
-  {at: 0, is: 'rotate(90deg) skew(10deg, 20deg)'},
-  {at: 0.25, is: 'rotate(135deg) skew(10deg, 20deg)'},
-  {at: 0.5, is: 'rotate(180deg) skew(10deg, 20deg)'},
-  {at: 0.75, is: 'rotate(225deg) skew(10deg, 20deg)'},
-  {at: 1, is: 'rotate(270deg) skew(10deg, 20deg)'},
-  {at: 1.5, is: 'rotate(360deg) skew(10deg, 20deg)'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/composition/transform-scale-composition.html b/third_party/blink/web_tests/animations/composition/transform-scale-composition.html
deleted file mode 100644
index 560f10ec..0000000
--- a/third_party/blink/web_tests/animations/composition/transform-scale-composition.html
+++ /dev/null
@@ -1,122 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<body>
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-// Addition (aka concatenation) of scale functions results in multiplying their
-// values (scale(2) scale(3) == scale(6)), whereas accumulation does a 1-based
-// sum of the components (accumulate(scale(2), scale(3)) == scale(2 + 3 - 1) ==
-// scale(4)).
-
-// ------------ Addition tests --------------
-
-assertComposition({
-  property: 'transform',
-  underlying: 'scaleX(2)',
-  addFrom: 'scaleX(3)',
-  addTo: 'scaleX(4)',
-}, [
-  {at: -0.5, is: 'scaleX(5)'},
-  {at: 0, is: 'scaleX(6)'},
-  {at: 0.25, is: 'scaleX(6.5)'},
-  {at: 0.5, is: 'scaleX(7)'},
-  {at: 0.75, is: 'scaleX(7.5)'},
-  {at: 1, is: 'scaleX(8)'},
-  {at: 1.5, is: 'scaleX(9)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  underlying: 'scaleY(2)',
-  addFrom: 'scaleY(3)',
-  addTo: 'scaleY(4)',
-}, [
-  {at: -0.5, is: 'scaleY(5)'},
-  {at: 0, is: 'scaleY(6)'},
-  {at: 0.25, is: 'scaleY(6.5)'},
-  {at: 0.5, is: 'scaleY(7)'},
-  {at: 0.75, is: 'scaleY(7.5)'},
-  {at: 1, is: 'scaleY(8)'},
-  {at: 1.5, is: 'scaleY(9)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  underlying: 'scaleZ(2)',
-  addFrom: 'scaleZ(3)',
-  addTo: 'scaleZ(4)',
-}, [
-  {at: -0.5, is: 'scaleZ(5)'},
-  {at: 0, is: 'scaleZ(6)'},
-  {at: 0.25, is: 'scaleZ(6.5)'},
-  {at: 0.5, is: 'scaleZ(7)'},
-  {at: 0.75, is: 'scaleZ(7.5)'},
-  {at: 1, is: 'scaleZ(8)'},
-  {at: 1.5, is: 'scaleZ(9)'},
-]);
-
-// ------------ Accumulation tests --------------
-
-assertComposition({
-  property: 'transform',
-  underlying: 'scaleX(2)',
-  accumulateFrom: 'scaleX(3)',
-  accumulateTo: 'scaleX(4)',
-}, [
-  {at: -0.5, is: 'scaleX(3.5)'},
-  {at: 0, is: 'scaleX(4)'},
-  {at: 0.25, is: 'scaleX(4.25)'},
-  {at: 0.5, is: 'scaleX(4.5)'},
-  {at: 0.75, is: 'scaleX(4.75)'},
-  {at: 1, is: 'scaleX(5)'},
-  {at: 1.5, is: 'scaleX(5.5)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  underlying: 'scaleY(2)',
-  accumulateFrom: 'scaleY(3)',
-  accumulateTo: 'scaleY(4)',
-}, [
-  {at: -0.5, is: 'scaleY(3.5)'},
-  {at: 0, is: 'scaleY(4)'},
-  {at: 0.25, is: 'scaleY(4.25)'},
-  {at: 0.5, is: 'scaleY(4.5)'},
-  {at: 0.75, is: 'scaleY(4.75)'},
-  {at: 1, is: 'scaleY(5)'},
-  {at: 1.5, is: 'scaleY(5.5)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  underlying: 'scaleZ(2)',
-  accumulateFrom: 'scaleZ(3)',
-  accumulateTo: 'scaleZ(4)',
-}, [
-  {at: -0.5, is: 'scaleZ(3.5)'},
-  {at: 0, is: 'scaleZ(4)'},
-  {at: 0.25, is: 'scaleZ(4.25)'},
-  {at: 0.5, is: 'scaleZ(4.5)'},
-  {at: 0.75, is: 'scaleZ(4.75)'},
-  {at: 1, is: 'scaleZ(5)'},
-  {at: 1.5, is: 'scaleZ(5.5)'},
-]);
-
-// The scale functions all share the same primitive type (scale3d), so can be
-// accumulated between.
-assertComposition({
-  property: 'transform',
-  underlying: 'scale(2, 4)',
-  accumulateFrom: 'scaleZ(3)',
-  accumulateTo: 'scaleZ(4)',
-}, [
-  {at: -0.5, is: 'scale3d(2, 4, 2.5)'},
-  {at: 0, is: 'scale3d(2, 4, 3)'},
-  {at: 0.25, is: 'scale3d(2, 4, 3.25)'},
-  {at: 0.5, is: 'scale3d(2, 4, 3.5)'},
-  {at: 0.75, is: 'scale3d(2, 4, 3.75)'},
-  {at: 1, is: 'scale3d(2, 4, 4)'},
-  {at: 1.5, is: 'scale3d(2, 4, 4.5)'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/composition/transform-skew-composition.html b/third_party/blink/web_tests/animations/composition/transform-skew-composition.html
deleted file mode 100644
index fc2f32f..0000000
--- a/third_party/blink/web_tests/animations/composition/transform-skew-composition.html
+++ /dev/null
@@ -1,117 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<body>
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-// Addition (aka concatenation) of two skew functions skew(a) and skew(b)
-// results in computing tan(a) + tan(b), whereas accumulation results in summing
-// the components to get tan(a + b).
-
-// ------------ Addition tests --------------
-
-assertComposition({
-  property: 'transform',
-  underlying: 'skewX(10deg)',
-  addFrom: 'skewX(30deg)',
-  addTo: 'skewX(50deg)',
-}, [
-  {at: -0.5, is: 'skewX(10deg) skewX(20deg)'},
-  {at: 0, is: 'skewX(10deg) skewX(30deg)'},
-  {at: 0.25, is: 'skewX(10deg) skewX(35deg)'},
-  {at: 0.5, is: 'skewX(10deg) skewX(40deg)'},
-  {at: 0.75, is: 'skewX(10deg) skewX(45deg)'},
-  {at: 1, is: 'skewX(10deg) skewX(50deg)'},
-  {at: 1.5, is: 'skewX(10deg) skewX(60deg)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  underlying: 'skewY(10deg)',
-  addFrom: 'skewY(30deg)',
-  addTo: 'skewY(50deg)',
-}, [
-  {at: -0.5, is: 'skewY(10deg) skewY(20deg)'},
-  {at: 0, is: 'skewY(10deg) skewY(30deg)'},
-  {at: 0.25, is: 'skewY(10deg) skewY(35deg)'},
-  {at: 0.5, is: 'skewY(10deg) skewY(40deg)'},
-  {at: 0.75, is: 'skewY(10deg) skewY(45deg)'},
-  {at: 1, is: 'skewY(10deg) skewY(50deg)'},
-  {at: 1.5, is: 'skewY(10deg) skewY(60deg)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  underlying: 'skew(10deg, 20deg)',
-  addFrom: 'skew(30deg, 10deg)',
-  addTo: 'skew(50deg, 50deg)',
-}, [
-  {at: -0.5, is: 'skew(10deg, 20deg) skew(20deg, -10deg)'},
-  {at: 0, is: 'skew(10deg, 20deg) skew(30deg, 10deg)'},
-  {at: 0.25, is: 'skew(10deg, 20deg) skew(35deg, 20deg)'},
-  {at: 0.5, is: 'skew(10deg, 20deg) skew(40deg, 30deg)'},
-  {at: 0.75, is: 'skew(10deg, 20deg) skew(45deg, 40deg)'},
-  {at: 1, is: 'skew(10deg, 20deg) skew(50deg, 50deg)'},
-  {at: 1.5, is: 'skew(10deg, 20deg) skew(60deg, 70deg)'},
-]);
-
-// ------------ Accumulation tests --------------
-
-assertComposition({
-  property: 'transform',
-  underlying: 'skewX(45deg)',
-  accumulateFrom: 'skewX(30deg)',
-  accumulateTo: 'skewX(70deg)',
-}, [
-  {at: -0.5, is: 'skewX(55deg)'},
-  {at: 0, is: 'skewX(75deg)'},
-  {at: 0.25, is: 'skewX(85deg)'},
-  {at: 0.5, is: 'skewX(95deg)'},
-  {at: 0.75, is: 'skewX(105deg)'},
-  {at: 1, is: 'skewX(115deg)'},
-  {at: 1.5, is: 'skewX(135deg)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  underlying: 'skewY(45deg)',
-  accumulateFrom: 'skewY(30deg)',
-  accumulateTo: 'skewY(70deg)',
-}, [
-  {at: -0.5, is: 'skewY(55deg)'},
-  {at: 0, is: 'skewY(75deg)'},
-  {at: 0.25, is: 'skewY(85deg)'},
-  {at: 0.5, is: 'skewY(95deg)'},
-  {at: 0.75, is: 'skewY(105deg)'},
-  {at: 1, is: 'skewY(115deg)'},
-  {at: 1.5, is: 'skewY(135deg)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  underlying: 'skew(10deg, 45deg)',
-  accumulateFrom: 'skew(20deg, 30deg)',
-  accumulateTo: 'skew(40deg, 70deg)',
-}, [
-  {at: -0.5, is: 'skew(20deg, 55deg)'},
-  {at: 0, is: 'skew(30deg, 75deg)'},
-  {at: 0.25, is: 'skew(35deg, 85deg)'},
-  {at: 0.5, is: 'skew(40deg, 95deg)'},
-  {at: 0.75, is: 'skew(45deg, 105deg)'},
-  {at: 1, is: 'skew(50deg, 115deg)'},
-  {at: 1.5, is: 'skew(60deg, 135deg)'},
-]);
-
-// The skew{X,Y} functions DO NOT share the same primitive type, so cannot be
-// accumlated between directly. Instead, they fall back to matrix accumulation,
-// which this tests for.
-assertComposition({
-  property: 'transform',
-  underlying: 'skewX(45deg)',
-  accumulateFrom: 'skewY(45deg)',
-  accumulateTo: 'skewY(45deg)',
-}, [
-  // Note that this is not equivalent to any form of combined skews.
-  {at: 0.5, is: 'matrix(1, 1, 0.5, 1.5, 0, 0)'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/composition/transform-translate-composition.html b/third_party/blink/web_tests/animations/composition/transform-translate-composition.html
deleted file mode 100644
index 65755dc..0000000
--- a/third_party/blink/web_tests/animations/composition/transform-translate-composition.html
+++ /dev/null
@@ -1,139 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<body>
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-// ------------ Addition tests --------------
-
-assertComposition({
-  property: 'transform',
-  underlying: 'translate(10px, 20px)',
-  addFrom: 'translate(100px, 200px)',
-  addTo: 'translate(200px, 400px)',
-}, [
-  {at: -0.5, is: 'translate(60px, 120px)'},
-  {at: 0, is: 'translate(110px, 220px)'},
-  {at: 0.25, is: 'translate(135px, 270px)'},
-  {at: 0.5, is: 'translate(160px, 320px)'},
-  {at: 0.75, is: 'translate(185px, 370px)'},
-  {at: 1, is: 'translate(210px, 420px)'},
-  {at: 1.5, is: 'translate(260px, 520px)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  underlying: 'translate(10px, 20px)',
-  addFrom: 'translate(100px, 200px)',
-  replaceTo: 'translate(210px, 420px)',
-}, [
-  {at: -0.5, is: 'translate(60px, 120px)'},
-  {at: 0, is: 'translate(110px, 220px)'},
-  {at: 0.25, is: 'translate(135px, 270px)'},
-  {at: 0.5, is: 'translate(160px, 320px)'},
-  {at: 0.75, is: 'translate(185px, 370px)'},
-  {at: 1, is: 'translate(210px, 420px)'},
-  {at: 1.5, is: 'translate(260px, 520px)'},
-]);
-
-// When testing translate functions in isolation, the additive and accumulation
-// behaviors are functionally identical. This test includes a rotate to ensure
-// both methods are implemented; add should append the from/to after the rotate.
-assertComposition({
-  property: 'transform',
-  underlying: 'translateX(100px) rotate(90deg)',
-  addFrom: 'translateX(100px)',
-  addTo: 'translateX(200px)',
-}, [
-  {at: -0.5, is: 'translateX(100px) rotate(90deg) translateX(50px)'},
-  {at: 0, is: 'translateX(100px) rotate(90deg) translateX(100px)'},
-  {at: 0.25, is: 'translateX(100px) rotate(90deg) translateX(125px)'},
-  {at: 0.5, is: 'translateX(100px) rotate(90deg) translateX(150px)'},
-  {at: 0.75, is: 'translateX(100px) rotate(90deg) translateX(175px)'},
-  {at: 1, is: 'translateX(100px) rotate(90deg) translateX(200px)'},
-  {at: 1.5, is: 'translateX(100px) rotate(90deg) translateX(250px)'},
-]);
-
-// ------------ Accumulation tests --------------
-
-assertComposition({
-  property: 'transform',
-  underlying: 'translateX(100px)',
-  accumulateFrom: 'translateX(50px)',
-  accumulateTo: 'translateX(250px)',
-}, [
-  {at: -0.5, is: 'translateX(50px)'},
-  {at: 0, is: 'translateX(150px)'},
-  {at: 0.25, is: 'translateX(200px)'},
-  {at: 0.5, is: 'translateX(250px)'},
-  {at: 0.75, is: 'translateX(300px)'},
-  {at: 1, is: 'translateX(350px)'},
-  {at: 1.5, is: 'translateX(450px)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  underlying: 'translateY(100px)',
-  accumulateFrom: 'translateY(50px)',
-  accumulateTo: 'translateY(250px)',
-}, [
-  {at: -0.5, is: 'translateY(50px)'},
-  {at: 0, is: 'translateY(150px)'},
-  {at: 0.25, is: 'translateY(200px)'},
-  {at: 0.5, is: 'translateY(250px)'},
-  {at: 0.75, is: 'translateY(300px)'},
-  {at: 1, is: 'translateY(350px)'},
-  {at: 1.5, is: 'translateY(450px)'},
-]);
-
-assertComposition({
-  property: 'transform',
-  underlying: 'translateZ(100px)',
-  accumulateFrom: 'translateZ(50px)',
-  accumulateTo: 'translateZ(250px)',
-}, [
-  {at: -0.5, is: 'translateZ(50px)'},
-  {at: 0, is: 'translateZ(150px)'},
-  {at: 0.25, is: 'translateZ(200px)'},
-  {at: 0.5, is: 'translateZ(250px)'},
-  {at: 0.75, is: 'translateZ(300px)'},
-  {at: 1, is: 'translateZ(350px)'},
-  {at: 1.5, is: 'translateZ(450px)'},
-]);
-
-// The translate functions all share the same primitive type (translate3d), so
-// can be accumulated between.
-assertComposition({
-  property: 'transform',
-  underlying: 'translate(100px, 50px)',
-  accumulateFrom: 'translateZ(50px)',
-  accumulateTo: 'translateZ(250px)',
-}, [
-  {at: -0.5, is: 'translate3d(100px, 50px, -50px)'},
-  {at: 0, is: 'translate3d(100px, 50px, 50px)'},
-  {at: 0.25, is: 'translate3d(100px, 50px, 100px)'},
-  {at: 0.5, is: 'translate3d(100px, 50px, 150px)'},
-  {at: 0.75, is: 'translate3d(100px, 50px, 200px)'},
-  {at: 1, is: 'translate3d(100px, 50px, 250px)'},
-  {at: 1.5, is: 'translate3d(100px, 50px, 350px)'},
-]);
-
-// When testing translate functions in isolation, the additive and accumulation
-// behaviors are functionally identical. This test includes a rotate to ensure
-// both methods are implemented; accumulate should combine the transform before
-// the rotate.
-assertComposition({
-  property: 'transform',
-  underlying: 'translateX(100px) rotate(90deg)',
-  accumulateFrom: 'translateX(100px)',
-  accumulateTo: 'translateX(200px)',
-}, [
-  {at: -0.5, is: 'translateX(150px) rotate(90deg)'},
-  {at: 0, is: 'translateX(200px) rotate(90deg)'},
-  {at: 0.25, is: 'translateX(225px) rotate(90deg)'},
-  {at: 0.5, is: 'translateX(250px) rotate(90deg)'},
-  {at: 0.75, is: 'translateX(275px) rotate(90deg)'},
-  {at: 1, is: 'translateX(300px) rotate(90deg)'},
-  {at: 1.5, is: 'translateX(350px) rotate(90deg)'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/composition/translate-composition.html b/third_party/blink/web_tests/animations/composition/translate-composition.html
deleted file mode 100644
index 342ff4c1..0000000
--- a/third_party/blink/web_tests/animations/composition/translate-composition.html
+++ /dev/null
@@ -1,139 +0,0 @@
-<!DOCTYPE html>
-<body>
-<style>
-.target {
-  width: 100px;
-  height: 100px;
-}
-</style>
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-assertComposition({
-  property: 'translate',
-  underlying: '100px 200px 300px',
-  addFrom: '-50px 50%',
-  addTo: '100%',
-}, [
-  {at: -1, is: '-100% calc(200px + 100%) 300px'},
-  {at: 0, is: '50px calc(200px + 50%) 300px'},
-  {at: 0.25, is: 'calc(62.5px + 25%) calc(200px + 37.5%) 300px'},
-  {at: 0.75, is: 'calc(87.5px + 75%) calc(200px + 12.5%) 300px'},
-  {at: 1, is: 'calc(100px + 100%) 200px 300px'},
-  {at: 2, is: 'calc(150px + 200%) calc(200px - 50%) 300px'},
-]);
-
-assertComposition({
-  property: 'translate',
-  underlying: '100px 200px 300px',
-  addFrom: '50% 100px',
-  replaceTo: '200px 50% 100px',
-}, [
-  {at: -1, is: '100% calc(600px - 50%) 500px'},
-  {at: 0, is: 'calc(100px + 50%) 300px 300px'},
-  {at: 0.25, is: 'calc(125px + 37.5%) calc(225px + 12.5%) 250px'},
-  {at: 0.75, is: 'calc(175px + 12.5%) calc(75px + 37.5%) 150px'},
-  {at: 1, is: '200px 50% 100px'},
-  {at: 2, is: 'calc(300px - 50%) calc(-300px + 100%) -100px'},
-]);
-
-assertComposition({
-  property: 'translate',
-  underlying: '100px 200px 300px',
-  replaceFrom: '50% 100px',
-  addTo: '200px 50% 100px',
-}, [
-  {at: -1, is: 'calc(-300px + 100%) -50% -400px'},
-  {at: 0, is: '50% 100px'},
-  {at: 0.25, is: 'calc(75px + 37.5%) calc(125px + 12.5%) 100px'},
-  {at: 0.75, is: 'calc(225px + 12.5%) calc(175px + 37.5%) 300px'},
-  {at: 1, is: '300px calc(200px + 50%) 400px'},
-  {at: 2, is: 'calc(600px - 50%) calc(300px + 100%) 800px'},
-]);
-
-assertComposition({
-  property: 'translate',
-  underlying: 'none',
-  replaceFrom: 'none',
-  addTo: '100px',
-}, [
-  {at: -1, is: '-100px'},
-  {at: 0, is: 'none'},
-  {at: 0.25, is: '25px'},
-  {at: 0.75, is: '75px'},
-  {at: 1, is: '100px'},
-  {at: 2, is: '200px'},
-]);
-
-assertComposition({
-  property: 'translate',
-  underlying: 'none',
-  addFrom: 'none',
-  addTo: '100px',
-}, [
-  {at: -1, is: '-100px'},
-  {at: 0, is: 'none'},
-  {at: 0.25, is: '25px'},
-  {at: 0.75, is: '75px'},
-  {at: 1, is: '100px'},
-  {at: 2, is: '200px'},
-]);
-
-assertComposition({
-  property: 'translate',
-  underlying: 'none',
-  replaceFrom: '0px 40px 60px',
-  replaceTo: 'none',
-}, [
-  {at: -1, is: '0px 80px 120px'},
-  {at: 0, is: '0px 40px 60px'},
-  {at: 0.25, is: '0px 30px 45px'},
-  {at: 0.75, is: '0px 10px 15px'},
-  {at: 1, is: 'none'},
-  {at: 2, is: '0px -40px -60px'},
-]);
-
-assertComposition({
-  property: 'translate',
-  underlying: 'none',
-  replaceFrom: '0px 40px 60px',
-  addTo: 'none',
-}, [
-  {at: -1, is: '0px 80px 120px'},
-  {at: 0, is: '0px 40px 60px'},
-  {at: 0.25, is: '0px 30px 45px'},
-  {at: 0.75, is: '0px 10px 15px'},
-  {at: 1, is: 'none'},
-  {at: 2, is: '0px -40px -60px'},
-]);
-
-assertComposition({
-  property: 'translate',
-  underlying: '80px 20px',
-  addFrom: 'none',
-  replaceTo: '0px 40px 60px',
-}, [
-  {at: -1, is: '160px 0px -60px'},
-  {at: 0, is: '80px 20px'},
-  {at: 0.25, is: '60px 25px 15px'},
-  {at: 0.5, is: '40px 30px 30px'},
-  {at: 0.75, is: '20px 35px 45px'},
-  {at: 1, is: '0px 40px 60px'},
-  {at: 2, is: '-80px 60px 120px'},
-]);
-
-assertComposition({
-  property: 'translate',
-  underlying: '80px 20px',
-  addFrom: '0px 40px 60px',
-  replaceTo: 'none',
-}, [
-  {at: -1, is: '160px 120px 120px'},
-  {at: 0, is: '80px 60px 60px'},
-  {at: 0.25, is: '60px 45px 45px'},
-  {at: 0.5, is: '40px 30px 30px'},
-  {at: 0.75, is: '20px 15px 15px'},
-  {at: 1, is: 'none'},
-  {at: 2, is: '-80px -60px -60px'},
-]);
-</script>
-</body>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/animations/composition/vertical-align-composition.html b/third_party/blink/web_tests/animations/composition/vertical-align-composition.html
deleted file mode 100644
index 515e7c9f..0000000
--- a/third_party/blink/web_tests/animations/composition/vertical-align-composition.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<body>
-<script src="../interpolation/resources/interpolation-test.js"></script>
-<script>
-assertComposition({
-  property: 'vertical-align',
-  underlying: '50px',
-  addFrom: '100px',
-  addTo: '200px',
-}, [
-  {at: -0.3, is: '120px'},
-  {at: 0, is: '150px'},
-  {at: 0.5, is: '200px'},
-  {at: 1, is: '250px'},
-  {at: 1.5, is: '300px'},
-]);
-
-assertComposition({
-  property: 'vertical-align',
-  underlying: '100px',
-  addFrom: '10px',
-  addTo: '2px',
-}, [
-  {at: -0.5, is: '114px'},
-  {at: 0, is: '110px'},
-  {at: 0.5, is: '106px'},
-  {at: 1, is: '102px'},
-  {at: 1.5, is: '98px'},
-]);
-
-assertComposition({
-  property: 'vertical-align',
-  underlying: '10%',
-  addFrom: '100px',
-  addTo: '20%',
-}, [
-  {at: -0.3, is: 'calc(130px + 4%)'},
-  {at: 0, is: 'calc(100px + 10%)'},
-  {at: 0.5, is: 'calc(50px + 20%)'},
-  {at: 1, is: '30%'},
-  {at: 1.5, is: 'calc(-50px + 40%)'},
-]);
-
-assertComposition({
-  property: 'vertical-align',
-  underlying: '50px',
-  addFrom: '100px',
-  replaceTo: '200px',
-}, [
-  {at: -0.3, is: '135px'},
-  {at: 0, is: '150px'},
-  {at: 0.5, is: '175px'},
-  {at: 1, is: '200px'},
-  {at: 1.5, is: '225px'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/compositing/overflow/scroller-with-border-radius-expected.html b/third_party/blink/web_tests/compositing/overflow/scroller-with-border-radius-expected.html
index 3b5c4b9..e9ed5eb 100644
--- a/third_party/blink/web_tests/compositing/overflow/scroller-with-border-radius-expected.html
+++ b/third_party/blink/web_tests/compositing/overflow/scroller-with-border-radius-expected.html
@@ -6,6 +6,7 @@
     width: 300px;
     background-color: red;
     border-radius: 5px;
+    will-change: transform;
 }
 
 #scrolled {
@@ -25,5 +26,5 @@
 </style>
 <div id="scroller">
     <div id="scrolled"></div>
-    <div id="fixed"></div>
 </div>
+<div id="fixed"></div>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index 75e660f..3f5bd019 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -142812,15 +142812,6 @@
    "css/css-grid/abspos/support/positioned-grid-descendants.js": [
     []
    ],
-   "css/css-grid/alignment/grid-align-content-distribution-expected.txt": [
-    []
-   ],
-   "css/css-grid/alignment/grid-align-content-distribution-vertical-lr-expected.txt": [
-    []
-   ],
-   "css/css-grid/alignment/grid-align-content-distribution-vertical-rl-expected.txt": [
-    []
-   ],
    "css/css-grid/alignment/grid-self-alignment-baseline-with-grid-001-ref.html": [
     []
    ],
@@ -214456,24 +214447,6 @@
      {}
     ]
    ],
-   "css/css-grid/alignment/grid-align-content-distribution-vertical-lr.html": [
-    [
-     "css/css-grid/alignment/grid-align-content-distribution-vertical-lr.html",
-     {}
-    ]
-   ],
-   "css/css-grid/alignment/grid-align-content-distribution-vertical-rl.html": [
-    [
-     "css/css-grid/alignment/grid-align-content-distribution-vertical-rl.html",
-     {}
-    ]
-   ],
-   "css/css-grid/alignment/grid-align-content-distribution.html": [
-    [
-     "css/css-grid/alignment/grid-align-content-distribution.html",
-     {}
-    ]
-   ],
    "css/css-grid/alignment/grid-align-content.html": [
     [
      "css/css-grid/alignment/grid-align-content.html",
@@ -219144,6 +219117,18 @@
      {}
     ]
    ],
+   "css/css-scroll-snap/snap-after-relayout/changing-scroll-snap-align.html": [
+    [
+     "css/css-scroll-snap/snap-after-relayout/changing-scroll-snap-align.html",
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/snap-after-relayout/changing-scroll-snap-type.html": [
+    [
+     "css/css-scroll-snap/snap-after-relayout/changing-scroll-snap-type.html",
+     {}
+    ]
+   ],
    "css/css-scroll-snap/snap-after-relayout/move-current-target.html": [
     [
      "css/css-scroll-snap/snap-after-relayout/move-current-target.html",
@@ -349274,7 +349259,7 @@
    "support"
   ],
   "clipboard-apis/async-interfaces.https.html": [
-   "e19c958f975d7967b8028a13d6901bdbd2ab4553",
+   "1c423e95b669a30a6af86db7a84d76a5a9c176b4",
    "testharness"
   ],
   "clipboard-apis/async-navigator-clipboard-basics.https.html": [
@@ -353182,11 +353167,11 @@
    "testharness"
   ],
   "cookies/http-state/general-tests-expected.txt": [
-   "4d33a0e1749dc71146976e8dfd43b2f5b5695749",
+   "330d89368b935b19bf0b67e599bae799f8301637",
    "support"
   ],
   "cookies/http-state/general-tests.html": [
-   "c8b7ea4ecb1c1203ad23afa5a6436693d4b125f6",
+   "d80527f9b0aa22c0611edff546d5663198a412bb",
    "testharness"
   ],
   "cookies/http-state/mozilla-tests-expected.txt": [
@@ -353226,7 +353211,7 @@
    "support"
   ],
   "cookies/http-state/resources/cookie-http-state-template.js": [
-   "62459f059fd147779354140d1e830ea52a263abe",
+   "b2af226e22ead4870133c402df00ca50cf9b0d97",
    "support"
   ],
   "cookies/http-state/resources/cookie-setter.py": [
@@ -353450,7 +353435,7 @@
    "support"
   ],
   "cookies/http-state/resources/test-files/0026-test": [
-   "609c6680b8281f845faa605b7d812bbecb8d615d",
+   "5ac72745f978b8394b583d10f1ae466d1055e2d4",
    "support"
   ],
   "cookies/http-state/resources/test-files/0027-expected": [
@@ -353462,11 +353447,11 @@
    "support"
   ],
   "cookies/http-state/resources/test-files/0028-expected": [
-   "609c6680b8281f845faa605b7d812bbecb8d615d",
+   "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
    "support"
   ],
   "cookies/http-state/resources/test-files/0028-test": [
-   "609c6680b8281f845faa605b7d812bbecb8d615d",
+   "fea1e1a643b97d4a101d704bd1497376a4997b3c",
    "support"
   ],
   "cookies/http-state/resources/test-files/attribute0001-expected": [
@@ -391025,30 +391010,6 @@
    "d45df4bc2231cbda5dee1bafc3f386f008024d79",
    "support"
   ],
-  "css/css-grid/alignment/grid-align-content-distribution-expected.txt": [
-   "29efcb5b4de0b02e99471433b0f12ca2d308cc51",
-   "support"
-  ],
-  "css/css-grid/alignment/grid-align-content-distribution-vertical-lr-expected.txt": [
-   "82b19bbbf0af70e6e43357a9083fc5a914c0da2f",
-   "support"
-  ],
-  "css/css-grid/alignment/grid-align-content-distribution-vertical-lr.html": [
-   "8217f4dd2c3cfd031aece87d54a78d5bcec640ca",
-   "testharness"
-  ],
-  "css/css-grid/alignment/grid-align-content-distribution-vertical-rl-expected.txt": [
-   "732395093c507177176642489e87db18a3554e18",
-   "support"
-  ],
-  "css/css-grid/alignment/grid-align-content-distribution-vertical-rl.html": [
-   "096e3fd6910a09ba5097b66acdb1dcf8a6d5326e",
-   "testharness"
-  ],
-  "css/css-grid/alignment/grid-align-content-distribution.html": [
-   "7b66ddb995191c67278d861aa6cb6a637bc6adaf",
-   "testharness"
-  ],
   "css/css-grid/alignment/grid-align-content.html": [
    "fb3f7007ee19189a09de9c1f786176c317b7ee14",
    "testharness"
@@ -402917,6 +402878,14 @@
    "d26359658f479c61df8d0a559fcb5558f63106a6",
    "testharness"
   ],
+  "css/css-scroll-snap/snap-after-relayout/changing-scroll-snap-align.html": [
+   "3be68fe841a0d6183b83d5b7287b70883c3cfce7",
+   "testharness"
+  ],
+  "css/css-scroll-snap/snap-after-relayout/changing-scroll-snap-type.html": [
+   "70774b3d40f691fe4feb623b4dfe430b12f4e8c0",
+   "testharness"
+  ],
   "css/css-scroll-snap/snap-after-relayout/move-current-target-expected.txt": [
    "3ba4afcb8454cdb40a8ae73254bfeb89ccd93ad3",
    "support"
@@ -475558,7 +475527,7 @@
    "support"
   ],
   "infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini": [
-   "c6f136d9715e86db9952dd6eac80b09b7782eed8",
+   "87726f492394955e3835a6a6675cae490669d5de",
    "support"
   ],
   "infrastructure/metadata/infrastructure/assumptions/document-fonts-ready.html.ini": [
@@ -477474,7 +477443,7 @@
    "testharness"
   ],
   "lint.whitelist": [
-   "62644762ce2bce2cbf0c3c8527cac8384ce00256",
+   "353922a456c4dbeacd2ab6d651b64be00c9a4903",
    "support"
   ],
   "loading/lazyload/META.yml": [
diff --git a/third_party/blink/web_tests/external/wpt/clipboard-apis/async-interfaces.https.html b/third_party/blink/web_tests/external/wpt/clipboard-apis/async-interfaces.https.html
index e19c958..1c423e9 100644
--- a/third_party/blink/web_tests/external/wpt/clipboard-apis/async-interfaces.https.html
+++ b/third_party/blink/web_tests/external/wpt/clipboard-apis/async-interfaces.https.html
@@ -9,12 +9,13 @@
 <script>
 'use strict';
 
-function doTest(idl, dom) {
+function doTest(idl, dom, html) {
   const idl_array = new IdlArray();
   idl_array.add_untested_idls('interface Navigator {};');
   idl_array.add_untested_idls('interface EventTarget {};');
   idl_array.add_untested_idls('dictionary PermissionDescriptor {};');
   idl_array.add_untested_idls(dom, { only: ['Event', 'EventInit'] });
+  idl_array.add_untested_idls(html, { only: ['DataTransfer', 'DataTransferItemList'] });
   idl_array.add_idls(idl);
   idl_array.add_objects({
     Navigator: ['navigator'],
@@ -33,7 +34,8 @@
     [
       '/interfaces/clipboard-apis.idl',
       '/interfaces/dom.idl',
+      '/interfaces/html.idl',
     ].map(fetchText))
-    .then(([idl, dom]) => doTest(idl, dom));
+    .then(([idl, dom, html]) => doTest(idl, dom, html));
 }, 'Test driver');
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-images/animations/object-position-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-images/animations/object-position-interpolation.html
deleted file mode 100644
index 055cbc8..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-images/animations/object-position-interpolation.html
+++ /dev/null
@@ -1,158 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<title>object-position-interpolation</title>
-<link rel="help" href="https://drafts.csswg.org/css-images-3/#the-object-position">
-<meta name="assert" content="object-position supports animation by computation">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/css/support/interpolation-testcommon.js"></script>
-
-<style>
-.parent {
-  object-position: 30px 10px;
-}
-
-.target {
-  position: relative;
-  width: 100px;
-  height: 100px;
-  background-color: black;
-  display: inline-block;
-  margin: 20px 0px 20px 0px;
-  object-fit: fill;
-  object-position: 10px 30px;
-}
-
-.expected {
-  background-color: green;
-}
-</style>
-<body>
-</body>
-<script>
-test_interpolation({
-  property: 'object-position',
-  from: neutralKeyframe,
-  to: '20px 20px',
-}, [
-  {at: -0.3, expect: '7px 33px'},
-  {at: 0, expect: '10px 30px'},
-  {at: 0.5, expect: '15px 25px'},
-  {at: 1, expect: '20px 20px'},
-  {at: 1.5, expect: '25px 15px'},
-]);
-
-test_interpolation({
-  property: 'object-position',
-  from: 'initial',
-  to: '20px 20px',
-}, [
-  {at: -0.3, expect: 'calc(-6px + 65%) calc(-6px + 65%)'},
-  {at: 0, expect: '50% 50%'},
-  {at: 0.5, expect: 'calc(10px + 25%) calc(10px + 25%)'},
-  {at: 1, expect: 'calc(20px + 0%) calc(20px + 0%)'},
-  {at: 1.5, expect: 'calc(30px + -25%) calc(30px + -25%)'},
-]);
-
-test_interpolation({
-  property: 'object-position',
-  from: 'inherit',
-  to: '20px 20px',
-}, [
-  {at: -0.3, expect: '33px 7px'},
-  {at: 0, expect: '30px 10px'},
-  {at: 0.5, expect: '25px 15px'},
-  {at: 1, expect: '20px 20px'},
-  {at: 1.5, expect: '15px 25px'},
-]);
-
-test_interpolation({
-  property: 'object-position',
-  from: 'unset',
-  to: '20px 20px',
-}, [
-  {at: -0.3, expect: 'calc(-6px + 65%) calc(-6px + 65%)'},
-  {at: 0, expect: '50% 50%'},
-  {at: 0.5, expect: 'calc(10px + 25%) calc(10px + 25%)'},
-  {at: 1, expect: 'calc(20px + 0%) calc(20px + 0%)'},
-  {at: 1.5, expect: 'calc(30px + -25%) calc(30px + -25%)'},
-]);
-
-test_interpolation({
-  property: 'object-position',
-  from: '50% 50%',
-  to: '100% 100%'
-}, [
-  {at: -0.3, expect: '35% 35%'},
-  {at: 0, expect: '50% 50%'},
-  {at: 0.5, expect: '75% 75%'},
-  {at: 1, expect: '100% 100%'},
-  {at: 1.5, expect: '125% 125%'}
-]);
-
-test_interpolation({
-  property: 'object-position',
-  from: '100px 200px',
-  to: '0px 0px'
-}, [
-  {at: -0.3, expect: '130px 260px'},
-  {at: 0, expect: '100px 200px'},
-  {at: 0.5, expect: '50px 100px'},
-  {at: 1, expect: '0px 0px'},
-  {at: 1.5, expect: '-50px -100px'}
-]);
-
-// Zero seem to be a special case in the old implementation
-test_interpolation({
-  property: 'object-position',
-  from: '50% 100%',
-  to: '0px 0px'
-}, [
-  {at: -0.3, expect: '65% 130%'},
-  {at: 0, expect: '50% 100%'},
-  {at: 0.5, expect: '25% 50%'},
-  {at: 1, expect: '0px 0px'},
-  {at: 1.5, expect: '-25% -50%'}
-]);
-
-test_interpolation({
-  property: 'object-position',
-  from: '50% 100%',
-  to: '50px 100px'
-}, [
-  {at: -0.3, expect: 'calc(65% + -15px) calc(130% + -30px)'},
-  {at: 0, expect: '50% 100%'},
-  {at: 0.5, expect: 'calc(25% + 25px) calc(50% + 50px)'},
-  {at: 1, expect: 'calc(0% + 50px) calc(0% + 100px)'},
-  {at: 1.5, expect: 'calc(-25% + 75px) calc(-50% + 150px)'}
-]);
-
-test_interpolation({
-  property: 'object-position',
-  from: 'center',
-  to: 'top right'
-}, [
-  {at: -0.3, expect: '35% 65%'},
-  {at: 0, expect: '50% 50%'},
-  {at: 0.5, expect: '75% 25%'},
-  {at: 1, expect: '100% 0%'},
-  {at: 1.5, expect: '125% -25%'}
-]);
-
-test_interpolation({
-  property: 'object-position',
-  from: 'center',
-  to: 'right 0% bottom 50%',
-}, [
-  {at: -0.5, expect: '25% 50%'},
-  {at: 0, expect: 'center'},
-  {at: 0.3, expect: '65% 50%'},
-  {at: 0.5, expect: '75% 50%'},
-  {at: 0.9, expect: '95% 50%'},
-  {at: 1, expect: '100% 50%'},
-  {at: 1.5, expect: '125% 50%'},
-  {at: 2, expect: '150% 50%'},
-]);
-</script>
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/animations/clip-path-composition.html b/third_party/blink/web_tests/external/wpt/css/css-masking/animations/clip-path-composition.html
new file mode 100644
index 0000000..2275ae70
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/animations/clip-path-composition.html
@@ -0,0 +1,189 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>clip-path composition</title>
+<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#the-clip-path">
+<meta name="assert" content="clip-path supports animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+  property: 'clip-path',
+  underlying: 'circle(100px at 25px 25%)',
+  addFrom: 'circle(10px at 25px 75%)',
+  addTo: 'circle(50px at 50px center)',
+}, [
+  {at: -0.3, expect: 'circle(98px at 42.5px 107.5%)'},
+  {at: 0, expect: 'circle(110px at 50px 100%)'},
+  {at: 0.3, expect: 'circle(122px at 57.5px 92.5%)'},
+  {at: 0.6, expect: 'circle(134px at 65px 85%)'},
+  {at: 1, expect: 'circle(150px at 75px 75%)'},
+  {at: 1.5, expect: 'circle(170px at 87.5px 62.5%)'},
+]);
+
+test_composition({
+  property: 'clip-path',
+  underlying: 'circle(100px at 20px 20%)',
+  addFrom: 'circle(50px at 50px 50%)',
+  replaceTo: 'circle(50% at 150px 150%)',
+}, [
+  {at: -0.3, expect: 'circle(calc(195px + -15%) at 46px 46%)'},
+  {at: 0, expect: 'circle(calc(150px + 0%) at 70px 70%)'},
+  {at: 0.3, expect: 'circle(calc(105px + 15%) at 94px 94%)'},
+  {at: 0.6, expect: 'circle(calc(60px + 30%) at 118px 118%)'},
+  {at: 1, expect: 'circle(50% at 150px 150%)'},
+  {at: 1.5, expect: 'circle(calc(-75px + 75%) at 190px 190%)'},
+]);
+
+test_composition({
+  property: 'clip-path',
+  underlying: 'circle(farthest-side at 25px 75%)',
+  addFrom: 'circle(farthest-side at 25px 75%)',
+  addTo: 'circle(farthest-side at 50px center)',
+}, [
+  {at: 0.25, expect: 'circle(farthest-side at 25px 75%)'},
+  {at: 0.75, expect: 'circle(farthest-side at 50px 50%)'},
+]);
+
+test_composition({
+  property: 'clip-path',
+  underlying: 'circle(50px at 10px 20px)',
+  addFrom: 'circle(50px at 10px 20px)',
+  addTo: 'circle(farthest-side at 30px 40px)',
+}, [
+  {at: 0.25, expect: 'circle(100px at 20px 40px)'},
+  {at: 0.75, expect: 'circle(farthest-side at 30px 40px)'},
+]);
+
+test_composition({
+  property: 'clip-path',
+  underlying: 'ellipse(10px 20px at 30px 40px)',
+  addFrom: 'ellipse(40px 30px at 20px 10px)',
+  addTo: 'ellipse(140px 130px at 120px 110px)',
+}, [
+  {at: -0.3, expect: 'ellipse(20px 20px at 20px 20px)'},
+  {at: 0, expect: 'ellipse(50px 50px at 50px 50px)'},
+  {at: 0.3, expect: 'ellipse(80px 80px at 80px 80px)'},
+  {at: 0.6, expect: 'ellipse(110px 110px at 110px 110px)'},
+  {at: 1, expect: 'ellipse(150px 150px at 150px 150px)'},
+  {at: 1.5, expect: 'ellipse(200px 200px at 200px 200px)'},
+]);
+
+test_composition({
+  property: 'clip-path',
+  underlying: 'ellipse(10px 20px at 30px 40px)',
+  replaceFrom: 'ellipse(40px 30px at 20px 10px)',
+  addTo: 'ellipse(40px 30px at 20px 10px)',
+}, [
+  {at: -0.3, expect: 'ellipse(37px 24px at 11px -2px)'},
+  {at: 0, expect: 'ellipse(40px 30px at 20px 10px)'},
+  {at: 0.3, expect: 'ellipse(43px 36px at 29px 22px)'},
+  {at: 0.6, expect: 'ellipse(46px 42px at 38px 34px)'},
+  {at: 1, expect: 'ellipse(50px 50px at 50px 50px)'},
+  {at: 1.5, expect: 'ellipse(55px 60px at 65px 70px)'},
+]);
+
+test_composition({
+  property: 'clip-path',
+  underlying: 'ellipse(25px 75%)',
+  addFrom: 'ellipse()',
+  addTo: 'ellipse(closest-side farthest-side)',
+}, [
+  {at: 0.25, expect: 'ellipse(at 50% 50%)'},
+  {at: 0.75, expect: 'ellipse(closest-side farthest-side at 50% 50%)'},
+]);
+
+test_composition({
+  property: 'clip-path',
+  underlying: 'inset(20px)',
+  addFrom: 'inset(20px)',
+  addTo: 'inset(40%)',
+}, [
+  {at: -0.3, expect: 'inset(calc(46px + -12%))'},
+  {at: 0, expect: 'inset(calc(40px + 0%))'},
+  {at: 0.3, expect: 'inset(calc(34px + 12%))'},
+  {at: 0.6, expect: 'inset(calc(28px + 24%))'},
+  {at: 1, expect: 'inset(calc(20px + 40%))'},
+  {at: 1.5, expect: 'inset(calc(10px + 60%))'},
+]);
+
+test_composition({
+  property: 'clip-path',
+  underlying: 'inset(1px 2px 3px 4px round 10px 20px 30px 40px / 50px 60px 70px 80px)',
+  addFrom: 'inset(1px 2px 3px 4px round 10px 20px 30px 40px / 50px 60px 70px 80px)',
+  replaceTo: 'inset(102px 104px 106px 108px round 120px 140px 160px 180px / 200px 220px 240px 260px)',
+}, [
+  {at: -0.3, expect: 'inset(-28px -26px -24px -22px round 0px 10px 30px 50px / 70px 90px 110px 130px)'},
+  {at: 0, expect: 'inset(2px 4px 6px 8px round 20px 40px 60px 80px / 100px 120px 140px 160px)'},
+  {at: 0.25, expect: 'inset(27px 29px 31px 33px round 45px 65px 85px 105px / 125px 145px 165px 185px)'},
+  {at: 0.75, expect: 'inset(77px 79px 81px 83px round 95px 115px 135px 155px / 175px 195px 215px 235px)'},
+  {at: 1, expect: 'inset(102px 104px 106px 108px round 120px 140px 160px 180px / 200px 220px 240px 260px)'},
+  {at: 1.5, expect: 'inset(152px 154px 156px 158px round 170px 190px 210px 230px / 250px 270px 290px 310px)'},
+]);
+
+test_composition({
+  property: 'clip-path',
+  underlying: 'inset(1px 2px round 100px 200px)',
+  addFrom: 'inset(1px 2px round 100px 200px)',
+  addTo: 'inset(101px 102px 101px 102px)',
+}, [
+  {at: -0.3, expect: 'inset(-28px -26px round 230px 460px)'},
+  {at: 0, expect: 'inset(2px 4px round 200px 400px)'},
+  {at: 0.3, expect: 'inset(32px 34px round 170px 340px)'},
+  {at: 0.6, expect: 'inset(62px 64px round 140px 280px)'},
+  {at: 1, expect: 'inset(102px 104px round 100px 200px)'},
+  {at: 1.5, expect: 'inset(152px 154px round 50px 100px)'},
+]);
+
+test_composition({
+  property: 'clip-path',
+  underlying: 'polygon(10px 20%, 30px 40%)',
+  addFrom: 'polygon(10px 20%, 30px 40%)',
+  addTo: 'polygon(110px 120%, 130px 140%)',
+}, [
+  {at: -0.3, expect: 'polygon(-10px 10%, 30px 50%)'},
+  {at: 0, expect: 'polygon(20px 40%, 60px 80%)'},
+  {at: 0.3, expect: 'polygon(50px 70%, 90px 110%)'},
+  {at: 0.6, expect: 'polygon(80px 100%, 120px 140%)'},
+  {at: 1, expect: 'polygon(120px 140%, 160px 180%)'},
+  {at: 1.5, expect: 'polygon(170px 190%, 210px 230%)'},
+]);
+
+test_composition({
+  property: 'clip-path',
+  underlying: 'polygon(evenodd, 10px 20px)',
+  addFrom: 'polygon(evenodd, 10px 20px)',
+  addTo: 'polygon(evenodd, 110px 120px)',
+}, [
+  {at: -0.3, expect: 'polygon(evenodd, -10px 10px)'},
+  {at: 0, expect: 'polygon(evenodd, 20px 40px)'},
+  {at: 0.3, expect: 'polygon(evenodd, 50px 70px)'},
+  {at: 0.6, expect: 'polygon(evenodd, 80px 100px)'},
+  {at: 1, expect: 'polygon(evenodd, 120px 140px)'},
+  {at: 1.5, expect: 'polygon(evenodd, 170px 190px)'},
+]);
+
+test_composition({
+  property: 'clip-path',
+  underlying: 'polygon(evenodd, 10px 20px)',
+  addFrom: 'polygon(evenodd, 10px 20px)',
+  addTo: 'polygon(nonzero, 30px 40px)',
+}, [
+  {at: 0.25, expect: 'polygon(evenodd, 20px 40px)'},
+  {at: 0.75, expect: 'polygon(30px 40px)'},
+]);
+
+test_composition({
+  property: 'clip-path',
+  underlying: 'polygon(10px 20px, 30px 40px)',
+  addFrom: 'polygon(10px 20px, 30px 40px)',
+  addTo: 'polygon(30px 40px)',
+}, [
+  {at: 0.25, expect: 'polygon(20px 40px, 60px 80px)'},
+  {at: 0.75, expect: 'polygon(30px 40px)'},
+]);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/animations/bottom-composition.html b/third_party/blink/web_tests/external/wpt/css/css-position/animations/bottom-composition.html
new file mode 100644
index 0000000..68a830d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/animations/bottom-composition.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>bottom composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#propdef-bottom">
+<meta name="assert" content="bottom support animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+  property: 'bottom',
+  underlying: '50px',
+  addFrom: '100px',
+  addTo: '200px',
+}, [
+  {at: -0.3, expect: '120px'},
+  {at: 0, expect: '150px'},
+  {at: 0.5, expect: '200px'},
+  {at: 1, expect: '250px'},
+  {at: 1.5, expect: '300px'},
+]);
+
+test_composition({
+  property: 'bottom',
+  underlying: '100px',
+  addFrom: '10px',
+  addTo: '2px',
+}, [
+  {at: -0.5, expect: '114px'},
+  {at: 0, expect: '110px'},
+  {at: 0.5, expect: '106px'},
+  {at: 1, expect: '102px'},
+  {at: 1.5, expect: '98px'},
+]);
+
+test_composition({
+  property: 'bottom',
+  underlying: '10%',
+  addFrom: '100px',
+  addTo: '20%',
+}, [
+  {at: -0.3, expect: 'calc(130px + 4%)'},
+  {at: 0, expect: 'calc(100px + 10%)'},
+  {at: 0.5, expect: 'calc(50px + 20%)'},
+  {at: 1, expect: '30%'},
+  {at: 1.5, expect: 'calc(-50px + 40%)'},
+]);
+
+test_composition({
+  property: 'bottom',
+  underlying: '50px',
+  addFrom: '100px',
+  replaceTo: '200px',
+}, [
+  {at: -0.3, expect: '135px'},
+  {at: 0, expect: '150px'},
+  {at: 0.5, expect: '175px'},
+  {at: 1, expect: '200px'},
+  {at: 1.5, expect: '225px'},
+]);
+
+test_composition({
+  property: 'bottom',
+  underlying: '100px',
+  addFrom: '100px',
+  addTo: 'auto',
+}, [
+  {at: -0.3, expect: '200px'},
+  {at: 0, expect: '200px'},
+  {at: 0.5, expect: 'auto'},
+  {at: 1, expect: 'auto'},
+  {at: 1.5, expect: 'auto'},
+]);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/animations/left-composition.html b/third_party/blink/web_tests/external/wpt/css/css-position/animations/left-composition.html
new file mode 100644
index 0000000..14b3dfd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/animations/left-composition.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>left composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#propdef-left">
+<meta name="assert" content="left support animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+  property: 'left',
+  underlying: '50px',
+  addFrom: '100px',
+  addTo: '200px',
+}, [
+  {at: -0.3, expect: '120px'},
+  {at: 0, expect: '150px'},
+  {at: 0.5, expect: '200px'},
+  {at: 1, expect: '250px'},
+  {at: 1.5, expect: '300px'},
+]);
+
+test_composition({
+  property: 'left',
+  underlying: '100px',
+  addFrom: '10px',
+  addTo: '2px',
+}, [
+  {at: -0.5, expect: '114px'},
+  {at: 0, expect: '110px'},
+  {at: 0.5, expect: '106px'},
+  {at: 1, expect: '102px'},
+  {at: 1.5, expect: '98px'},
+]);
+
+test_composition({
+  property: 'left',
+  underlying: '10%',
+  addFrom: '100px',
+  addTo: '20%',
+}, [
+  {at: -0.3, expect: 'calc(130px + 4%)'},
+  {at: 0, expect: 'calc(100px + 10%)'},
+  {at: 0.5, expect: 'calc(50px + 20%)'},
+  {at: 1, expect: '30%'},
+  {at: 1.5, expect: 'calc(-50px + 40%)'},
+]);
+
+test_composition({
+  property: 'left',
+  underlying: '10%',
+  addFrom: '100px',
+  addTo: '-10%',
+}, [
+  {at: -0.3, expect: 'calc(130px + 13%)'},
+  {at: 0, expect: 'calc(100px + 10%)'},
+  {at: 0.5, expect: 'calc(50px + 5%)'},
+  {at: 1, expect: '0%'},
+  {at: 1.5, expect: 'calc(-50px - 5%)'},
+]);
+
+test_composition({
+  property: 'left',
+  underlying: '50px',
+  addFrom: '100px',
+  replaceTo: '200px',
+}, [
+  {at: -0.3, expect: '135px'},
+  {at: 0, expect: '150px'},
+  {at: 0.5, expect: '175px'},
+  {at: 1, expect: '200px'},
+  {at: 1.5, expect: '225px'},
+]);
+
+test_composition({
+  property: 'left',
+  underlying: '100px',
+  addFrom: '100px',
+  addTo: 'auto',
+}, [
+  {at: -0.3, expect: '200px'},
+  {at: 0, expect: '200px'},
+  {at: 0.5, expect: 'auto'},
+  {at: 1, expect: 'auto'},
+  {at: 1.5, expect: 'auto'},
+]);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/animation/position-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-position/animations/position-interpolation.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-position/animation/position-interpolation.html
rename to third_party/blink/web_tests/external/wpt/css/css-position/animations/position-interpolation.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/animations/right-composition.html b/third_party/blink/web_tests/external/wpt/css/css-position/animations/right-composition.html
new file mode 100644
index 0000000..995bb8d6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/animations/right-composition.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>right composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#propdef-right">
+<meta name="assert" content="right support animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+  property: 'right',
+  underlying: '50px',
+  addFrom: '100px',
+  addTo: '200px',
+}, [
+  {at: -0.3, expect: '120px'},
+  {at: 0, expect: '150px'},
+  {at: 0.5, expect: '200px'},
+  {at: 1, expect: '250px'},
+  {at: 1.5, expect: '300px'},
+]);
+
+test_composition({
+  property: 'right',
+  underlying: '100px',
+  addFrom: '10px',
+  addTo: '2px',
+}, [
+  {at: -0.5, expect: '114px'},
+  {at: 0, expect: '110px'},
+  {at: 0.5, expect: '106px'},
+  {at: 1, expect: '102px'},
+  {at: 1.5, expect: '98px'},
+]);
+
+test_composition({
+  property: 'right',
+  underlying: '10%',
+  addFrom: '100px',
+  addTo: '20%',
+}, [
+  {at: -0.3, expect: 'calc(130px + 4%)'},
+  {at: 0, expect: 'calc(100px + 10%)'},
+  {at: 0.5, expect: 'calc(50px + 20%)'},
+  {at: 1, expect: '30%'},
+  {at: 1.5, expect: 'calc(-50px + 40%)'},
+]);
+
+test_composition({
+  property: 'right',
+  underlying: '50px',
+  addFrom: '100px',
+  replaceTo: '200px',
+}, [
+  {at: -0.3, expect: '135px'},
+  {at: 0, expect: '150px'},
+  {at: 0.5, expect: '175px'},
+  {at: 1, expect: '200px'},
+  {at: 1.5, expect: '225px'},
+]);
+
+test_composition({
+  property: 'right',
+  underlying: '100px',
+  addFrom: '100px',
+  addTo: 'auto',
+}, [
+  {at: -0.3, expect: '200px'},
+  {at: 0, expect: '200px'},
+  {at: 0.5, expect: 'auto'},
+  {at: 1, expect: 'auto'},
+  {at: 1.5, expect: 'auto'},
+]);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/animations/top-composition.html b/third_party/blink/web_tests/external/wpt/css/css-position/animations/top-composition.html
new file mode 100644
index 0000000..47782e8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/animations/top-composition.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>top composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#propdef-top">
+<meta name="assert" content="top support animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+  property: 'top',
+  underlying: '50px',
+  addFrom: '100px',
+  addTo: '200px',
+}, [
+  {at: -0.3, expect: '120px'},
+  {at: 0, expect: '150px'},
+  {at: 0.5, expect: '200px'},
+  {at: 1, expect: '250px'},
+  {at: 1.5, expect: '300px'},
+]);
+
+test_composition({
+  property: 'top',
+  underlying: '100px',
+  addFrom: '10px',
+  addTo: '2px',
+}, [
+  {at: -0.5, expect: '114px'},
+  {at: 0, expect: '110px'},
+  {at: 0.5, expect: '106px'},
+  {at: 1, expect: '102px'},
+  {at: 1.5, expect: '98px'},
+]);
+
+test_composition({
+  property: 'top',
+  underlying: '10%',
+  addFrom: '100px',
+  addTo: '20%',
+}, [
+  {at: -0.3, expect: 'calc(130px + 4%)'},
+  {at: 0, expect: 'calc(100px + 10%)'},
+  {at: 0.5, expect: 'calc(50px + 20%)'},
+  {at: 1, expect: '30%'},
+  {at: 1.5, expect: 'calc(-50px + 40%)'},
+]);
+
+test_composition({
+  property: 'top',
+  underlying: '50px',
+  addFrom: '100px',
+  replaceTo: '200px',
+}, [
+  {at: -0.3, expect: '135px'},
+  {at: 0, expect: '150px'},
+  {at: 0.5, expect: '175px'},
+  {at: 1, expect: '200px'},
+  {at: 1.5, expect: '225px'},
+]);
+
+test_composition({
+  property: 'top',
+  underlying: '100px',
+  addFrom: '100px',
+  addTo: 'auto',
+}, [
+  {at: -0.3, expect: '200px'},
+  {at: 0, expect: '200px'},
+  {at: 0.5, expect: 'auto'},
+  {at: 1, expect: 'auto'},
+  {at: 1.5, expect: 'auto'},
+]);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/perspective-composition.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/perspective-composition.html
new file mode 100644
index 0000000..6fa745d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/perspective-composition.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title> perspective composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#propdef-perspective">
+<meta name="assert" content="perspective supports animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+  property: 'perspective',
+  underlying: '50px',
+  addFrom: '100px',
+  addTo: '200px',
+}, [
+  {at: -0.3, expect: '120px'},
+  {at: 0, expect: '150px'},
+  {at: 0.5, expect: '200px'},
+  {at: 1, expect: '250px'},
+  {at: 1.5, expect: '300px'},
+]);
+
+test_composition({
+  property: 'perspective',
+  underlying: '100px',
+  addFrom: '10px',
+  addTo: '2px',
+}, [
+  {at: -0.5, expect: '114px'},
+  {at: 0, expect: '110px'},
+  {at: 0.5, expect: '106px'},
+  {at: 1, expect: '102px'},
+  {at: 1.5, expect: '98px'}, // Value clamping should happen after composition.
+]);
+
+test_composition({
+  property: 'perspective',
+  underlying: '50px',
+  addFrom: '100px',
+  replaceTo: '200px',
+}, [
+  {at: -0.3, expect: '135px'},
+  {at: 0, expect: '150px'},
+  {at: 0.5, expect: '175px'},
+  {at: 1, expect: '200px'},
+  {at: 1.5, expect: '225px'},
+]);
+
+test_composition({
+  property: 'perspective',
+  underlying: '100px',
+  addFrom: '100px',
+  addTo: 'none',
+}, [
+  {at: -0.3, expect: '200px'},
+  {at: 0, expect: '200px'},
+  {at: 0.5, expect: 'none'},
+  {at: 1, expect: 'none'},
+  {at: 1.5, expect: 'none'},
+]);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/rotate-composition.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/rotate-composition.html
new file mode 100644
index 0000000..fa0118d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/rotate-composition.html
@@ -0,0 +1,167 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title> rotate composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#propdef-rotate">
+<meta name="assert" content="rotate supports animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+  property: 'rotate',
+  underlying: '100deg',
+  addFrom: '10deg',
+  addTo: '30deg',
+}, [
+  {at: -1, expect: '90deg'},
+  {at: 0, expect: '110deg'},
+  {at: 0.25, expect: '115deg'},
+  {at: 0.75, expect: '125deg'},
+  {at: 1, expect: '130deg'},
+  {at: 2, expect: '150deg'},
+]);
+
+test_composition({
+  property: 'rotate',
+  underlying: '1 0 0 200deg',
+  addFrom: '1 0 0 -100deg',
+  replaceTo: '1 0 0 40deg',
+}, [
+  {at: -1, expect: '1 0 0 160deg'},
+  {at: 0, expect: '1 0 0 100deg'},
+  {at: 0.25, expect: '1 0 0 85deg'},
+  {at: 0.75, expect: '1 0 0 55deg'},
+  {at: 1, expect: '1 0 0 40deg'},
+  {at: 2, expect: '1 0 0 -20deg'},
+]);
+
+test_composition({
+  property: 'rotate',
+  underlying: '0 1 0 -40deg',
+  replaceFrom: '0 1 0 50deg',
+  addTo: '0 1 0 10deg',
+}, [
+  {at: -1, expect: '0 1 0 130deg'},
+  {at: 0, expect: '0 1 0 50deg'},
+  {at: 0.25, expect: '0 1 0 30deg'},
+  {at: 0.75, expect: '0 1 0 -10deg'},
+  {at: 1, expect: '0 1 0 -30deg'},
+  {at: 2, expect: '0 1 0 -110deg'},
+]);
+
+test_composition({
+  property: 'rotate',
+  underlying: '1 2 3 40deg',
+  addFrom: '2 4 6 10deg',
+  addTo: '3 6 9 50deg',
+}, [
+  {at: -1, expect: '1 2 3 10deg'},
+  {at: 0, expect: '1 2 3 50deg'},
+  {at: 0.25, expect: '1 2 3 60deg'},
+  {at: 0.75, expect: '1 2 3 80deg'},
+  {at: 1, expect: '1 2 3 90deg'},
+  {at: 2, expect: '1 2 3 130deg'},
+]);
+
+test_composition({
+  property: 'rotate',
+  underlying: '1 2 3 270deg',
+  addFrom: '1 2 3 90deg',
+  replaceTo: '0 1 0 100deg',
+}, [
+  {at: -1, expect: '-5.49276e-17 -1 -1.64783e-16 100deg'},
+  {at: 0, expect: '1 2 3 360deg'},
+  {at: 0.25, expect: '-1.20172e-16 1 -3.60516e-16 25deg'},
+  {at: 0.75, expect: '-1.51909e-17 1 -4.55726e-17 75deg'},
+  {at: 1, expect: '0 1 0 100deg'},
+  {at: 2, expect: '-3.3235e-17 -1 -9.97049e-17 160deg'},
+]);
+
+test_composition({
+  property: 'rotate',
+  underlying: '1 2 3 90deg',
+  addFrom: '2 4 6 270deg',
+  replaceTo: '0 1 0 100deg',
+}, [
+  {at: -1, expect: '-5.49276e-17 -1 -1.64783e-16 100deg'},
+  {at: 0, expect: '1 2 3 360deg'},
+  {at: 0.25, expect: '-1.20172e-16 1 -3.60516e-16 25deg'},
+  {at: 0.75, expect: '-1.51909e-17 1 -4.55726e-17 75deg'},
+  {at: 1, expect: '0 1 0 100deg'},
+  {at: 2, expect: '-3.3235e-17 -1 -9.97049e-17 160deg'},
+]);
+
+test_composition({
+  property: 'rotate',
+  underlying: '1 0 0 90deg',
+  addFrom: '0 1 0 180deg',
+  replaceTo: '0 0 1 90deg',
+}, [
+  {at: -1, expect: '-6.12323e-17 -1 1.57009e-16 90deg'},
+  {at: 0, expect: '-4.32978e-17 -0.707107 -0.707107 180deg'},
+  {at: 0.25, expect: '-1.48952e-16 -0.894427 -0.447214 131.81deg'},
+  {at: 0.75, expect: '-2.94392e-17 -0.707107 0.707107 70.5288deg'},
+  {at: 1, expect: '90deg'},
+  {at: 2, expect: '-6.12323e-17 -1 -4.71028e-16 90deg'},
+]);
+
+test_composition({
+  property: 'rotate',
+  underlying: 'none',
+  addFrom: 'none',
+  replaceTo: '0 1 0 100deg',
+}, [
+  {at: -1, expect: '0 1 0 -100deg'},
+  {at: 0, expect: 'none'},
+  {at: 0.25, expect: '0 1 0 25deg'},
+  {at: 0.75, expect: '0 1 0 75deg'},
+  {at: 1, expect: '0 1 0 100deg'},
+  {at: 2, expect: '0 1 0 200deg'},
+]);
+
+test_composition({
+  property: 'rotate',
+  underlying: 'none',
+  addFrom: '2 4 6 270deg',
+  replaceTo: 'none',
+}, [
+  {at: -1, expect: '2 4 6 540deg'},
+  {at: 0, expect: '2 4 6 270deg'},
+  {at: 0.25, expect: '2 4 6 202.5deg'},
+  {at: 0.75, expect: '2 4 6 67.5deg'},
+  {at: 1, expect: 'none'},
+  {at: 2, expect: '2 4 6 -270deg'},
+]);
+
+test_composition({
+  property: 'rotate',
+  underlying: '1 2 3 90deg',
+  addFrom: 'none',
+  replaceTo: '0 1 0 100deg',
+}, [
+  {at: -1, expect: '0.31 -0.22 0.92 131.66deg'},
+  {at: 0, expect: '1 2 3 90deg'},
+  {at: 0.25, expect: '0.21 0.73 0.64 86.72deg'},
+  {at: 0.75, expect: '0.07 0.97 0.21 92.05deg'},
+  {at: 1, expect: '0 1 0 100deg'},
+  {at: 2, expect: '-0.2 0.79 -0.59 151.11deg'},
+]);
+
+test_composition({
+  property: 'rotate',
+  underlying: '1 2 3 90deg',
+  addFrom: '2 4 6 270deg',
+  replaceTo: 'none',
+}, [
+  {at: -1, expect: '1 2 3 720deg'},
+  {at: 0, expect: '1 2 3 360deg'},
+  {at: 0.25, expect: '1 2 3 270deg'},
+  {at: 0.75, expect: '1 2 3 90deg'},
+  {at: 1, expect: 'none'},
+  {at: 2, expect: '1 2 3 -360deg'},
+]);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/scale-composition.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/scale-composition.html
new file mode 100644
index 0000000..6fc4de6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/scale-composition.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>scale composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#propdef-scale">
+<meta name="assert" content="scale supports animation.">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+  property: 'scale',
+  underlying: '2 1',
+  addFrom: '3 1',
+  addTo: '4 1',
+}, [
+  {at: -0.5, expect: '5 1'},
+  {at: 0, expect: '6 1'},
+  {at: 0.25, expect: '6.5 1'},
+  {at: 0.5, expect: '7 1'},
+  {at: 0.75, expect: '7.5 1'},
+  {at: 1, expect: '8 1'},
+  {at: 1.5, expect: '9 1'},
+]);
+
+test_composition({
+  property: 'scale',
+  underlying: '1 2 3',
+  addFrom: '4 5 6',
+  replaceTo: '7 8 9',
+}, [
+  {at: -0.5, expect: '2.5 11 22.5'},
+  {at: 0, expect: '4 10 18'},
+  {at: 0.25, expect: '4.75 9.5 15.75'},
+  {at: 0.5, expect: '5.5 9 13.5'},
+  {at: 0.75, expect: '6.25 8.5 11.25'},
+  {at: 1, expect: '7 8 9'},
+  {at: 1.5, expect: '8.5 7 4.5'},
+]);
+
+test_composition({
+  property: 'scale',
+  underlying: 'none',
+  addFrom: 'none',
+  replaceTo: '1.5 1',
+}, [
+  {at: -1, expect: '0.5 1'},
+  {at: 0, expect: '1'},
+  {at: 0.25, expect: '1.125 1'},
+  {at: 0.75, expect: '1.375 1'},
+  {at: 1, expect: '1.5 1'},
+  {at: 2, expect: '2 1'},
+]);
+
+test_composition({
+  property: 'scale',
+  underlying: 'none',
+  addFrom: '4 5 6',
+  replaceTo: 'none',
+}, [
+  {at: -1, expect: '7 9 11'},
+  {at: 0, expect: '4 5 6'},
+  {at: 0.25, expect: '3.25 4 4.75'},
+  {at: 0.75, expect: '1.75 2 2.25'},
+  {at: 1, expect: 'none'},
+  {at: 2, expect: '-2 -3 -4'},
+]);
+
+test_composition({
+  property: 'scale',
+  underlying: '1 2 3',
+  addFrom: 'none',
+  replaceTo: '7 8 9',
+}, [
+  {at: -0.5, expect: '-2 -1 0'},
+  {at: 0, expect: '1 2 3'},
+  {at: 0.25, expect: '2.5 3.5 4.5'},
+  {at: 0.5, expect: '4 5 6'},
+  {at: 0.75, expect: '5.5 6.5 7.5'},
+  {at: 1, expect: '7 8 9'},
+  {at: 1.5, expect: '10 11 12'},
+]);
+
+test_composition({
+  property: 'scale',
+  underlying: '1 2 3',
+  addFrom: '4 5 6',
+  replaceTo: 'none',
+}, [
+  {at: -0.5, expect: '5.5 14.5 26.5'},
+  {at: 0, expect: '4 10 18'},
+  {at: 0.25, expect: '3.25 7.75 13.75'},
+  {at: 0.5, expect: '2.5 5.5 9.5'},
+  {at: 0.75, expect: '1.75 3.25 5.25'},
+  {at: 1, expect: 'none'},
+  {at: 1.5, expect: '-0.5 -3.5 -7.5'},
+]);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-composition.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-composition.html
new file mode 100644
index 0000000..928da71a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-composition.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>transform composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-transforms/#transform-property">
+<meta name="assert" content="transform supports animation as a transform list">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+// This file contains tests for the composition behavior of transforms that is
+// unrelated to the individual transform functions. For the transform functions
+// themselves, see the transform-*-composition.html subtests.
+
+// ------------------ Addition -----------------
+test_composition({
+  property: 'transform',
+  underlying: 'rotateX(100deg) rotateY(100deg)',
+  addFrom: 'translate(10px, 20px)',
+  replaceTo: 'rotateX(200deg) rotateY(200deg) translate(110px, 220px)',
+}, [
+  {at: -0.5, expect: 'rotateX(50deg) rotateY(50deg) translate(-40px, -80px)'},
+  {at: 0, expect: 'rotateX(100deg) rotateY(100deg) translate(10px, 20px)'},
+  {at: 0.25, expect: 'rotateX(125deg) rotateY(125deg) translate(35px, 70px)'},
+  {at: 0.5, expect: 'rotateX(150deg) rotateY(150deg) translate(60px, 120px)'},
+  {at: 0.75, expect: 'rotateX(175deg) rotateY(175deg) translate(85px, 170px)'},
+  {at: 1, expect: 'rotateX(200deg) rotateY(200deg) translate(110px, 220px)'},
+  {at: 1.5, expect: 'rotateX(250deg) rotateY(250deg) translate(160px, 320px)'},
+]);
+
+// Shorter list is extended with corresponding identity transforms for pairwise
+// interpolation.
+test_composition({
+  property: 'transform',
+  underlying: 'rotateX(45deg)',
+  addFrom: 'none',
+  addTo: 'rotateY(360deg)',
+}, [
+  {at: -0.5, expect: 'rotateX(45deg) rotateY(-180deg)'},
+  {at: 0, expect: 'rotateX(45deg) rotateY(0deg)'},
+  {at: 0.25, expect: 'rotateX(45deg) rotateY(90deg)'},
+  {at: 0.5, expect: 'rotateX(45deg) rotateY(180deg)'},
+  {at: 0.75, expect: 'rotateX(45deg) rotateY(270deg)'},
+  {at: 1, expect: 'rotateX(45deg) rotateY(360deg)'},
+  {at: 1.5, expect: 'rotateX(45deg) rotateY(540deg)'},
+]);
+
+// Matrix decomposition cases
+test_composition({
+  property: 'transform',
+  underlying: 'rotateX(90deg)',
+  addFrom: 'translate(100px, 100px)',
+  addTo: 'scale(2)',
+}, [
+  {at: -0.5, expect: 'matrix3d(0.5, 0, 0, 0, 0, 1.11022e-16, 0.5, 0, 0, -1, 2.22045e-16, 0, 150, 9.18485e-15, 150, 1)'},
+  {at: 0, expect: 'matrix3d(1, 0, 0, 0, 0, 6.12323e-17, 1, 0, 0, -1, 6.12323e-17, 0, 100, 6.12323e-15, 100, 1)'},
+  {at: 0.25, expect: 'matrix3d(1.25, 0, 0, 0, 0, 2.77556e-16, 1.25, 0, 0, -1, 2.22045e-16, 0, 75, 4.59243e-15, 75, 1)'},
+  {at: 0.5, expect: 'matrix3d(1.5, 0, 0, 0, 0, 3.33067e-16, 1.5, 0, 0, -1, 2.22045e-16, 0, 50, 3.06162e-15, 50, 1)'},
+  {at: 0.75, expect: 'matrix3d(1.75, 0, 0, 0, 0, 3.88578e-16, 1.75, 0, 0, -1, 2.22045e-16, 0, 25, 1.53081e-15, 25, 1)'},
+  {at: 1, expect: 'matrix3d(2, 0, 0, 0, 0, 1.22465e-16, 2, 0, 0, -1, 6.12323e-17, 0, 0, 0, 0, 1)'},
+  {at: 1.5, expect: 'matrix3d(2.5, 0, 0, 0, 0, 5.55112e-16, 2.5, 0, 0, -1, 2.22045e-16, 0, -50, -3.06162e-15, -50, 1)'},
+]);
+
+// Force a fallback to matrix interpolation.
+test_composition({
+  property: 'transform',
+  underlying: 'rotateX(45deg)',
+  addFrom: 'scaleX(1)',
+  addTo: 'rotateY(360deg)',
+}, [
+  {at: -0.5, expect: 'rotateX(45deg)'},
+  {at: 0, expect: 'rotateX(45deg)'},
+  {at: 0.25, expect: 'rotateX(45deg)'},
+  {at: 0.5, expect: 'rotateX(45deg)'},
+  {at: 0.75, expect: 'rotateX(45deg)'},
+  {at: 1, expect: 'rotateX(45deg)'},
+  {at: 1.5, expect: 'rotateX(45deg)'},
+]);
+
+// ------------------ Accumulation -----------------
+
+// TODO(smcgruer): Add tests for accumulation behaviors.
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-matrix-composition.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-matrix-composition.html
new file mode 100644
index 0000000..2586ff3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-matrix-composition.html
@@ -0,0 +1,208 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>transform-matrix composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#ctm">
+<meta name="assert" content="transform-matrix supports animation as a transform list">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+// For matrix and matrix3d, addition is defined as concatenation whilst
+// accumulation works by decomposing the matrix and then accumulating the
+// decomposed functions. We can therefore test the difference between the
+// two by mixing functions such that a naive multiplication would look
+// different than the accumulation behavior.
+//
+// Note that due to the complexities of decomposition the test space here is
+// huge; we cover some basic cases and hope that the tests for the individual
+// functions provide a lot of the remaining coverage.
+
+// Creates a matrix3d function, encoding the passed rotation and translation.
+// Note that the translate will not be affected by the rotation.
+function create3dMatrix(x, y, z, radians, translateX) {
+  // Normalize the rotation axes.
+  const length = Math.sqrt(x*x + y*y + z*z);
+  x /= length;
+  y /= length;
+  z /= length;
+
+  const sc = Math.sin(radians / 2) * Math.cos(radians / 2);
+  const sq = Math.sin(radians / 2) * Math.sin(radians / 2);
+
+  // https://drafts.csswg.org/css-transforms-2/#Rotate3dDefined
+  // https://drafts.csswg.org/css-transforms-2/#Translate3dDefined
+  return 'matrix3d(' + [
+      1 - 2 * (y*y + z*z) * sq,
+      2 * (x * y * sq + z * sc),
+      2 * (x * z * sq - y * sc),
+      0,
+      2 * (x * y * sq - z * sc),
+      1 - 2 * (x*x + z*z) * sq,
+      2 * (y * z * sq + x * sc),
+      0,
+      2 * (x * z * sq + y * sc),
+      2 * (y * z * sq - x * sc),
+      1 - 2 * (x*x + y*y) * sq,
+      0,
+      translateX, 0, 0, 1].join() + ')';
+}
+
+// ------------ Addition tests --------------
+
+test_composition({
+  property: 'transform',
+  // translateX(100px) rotate(90deg)
+  underlying: 'matrix(0, 1, -1, 0, 100, 0)',
+  // translateX(100px)
+  addFrom: 'matrix(1, 0, 0, 1, 100, 0)',
+  // translateX(200px)
+  addTo: 'matrix(1, 0, 0, 1, 200, 0)',
+}, [
+  {at: -0.5, expect: 'matrix(0, 1, -1, 0, 100, 50)'},
+  {at: 0, expect: 'matrix(0, 1, -1, 0, 100, 100)'},
+  {at: 0.25, expect: 'matrix(0, 1, -1, 0, 100, 125)'},
+  {at: 0.5, expect: 'matrix(0, 1, -1, 0, 100, 150)'},
+  {at: 0.75, expect: 'matrix(0, 1, -1, 0, 100, 175)'},
+  {at: 1, expect: 'matrix(0, 1, -1, 0, 100, 200)'},
+  {at: 1.5, expect: 'matrix(0, 1, -1, 0, 100, 250)'},
+]);
+
+test_composition({
+  property: 'transform',
+  // translateX(100px) rotate3d(1, 1, 0, 45deg)
+  underlying: create3dMatrix(1, 1, 0, Math.PI / 4, 100),
+  // translateX(100px)
+  addFrom: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 100, 0, 0, 1)',
+  // translateX(200px)
+  addTo: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 200, 0, 0, 1)',
+}, [
+  // matrix3ds are hard to read; these are the decomposed forms for clarity
+  {at: -0.5, expect: 'translateX(100px) rotate3d(1, 1, 0, 45deg) translateX(50px)'},
+  {at: 0, expect: 'translateX(100px) rotate3d(1, 1, 0, 45deg) translateX(100px)'},
+  {at: 0.25, expect: 'translateX(100px) rotate3d(1, 1, 0, 45deg) translateX(125px)'},
+  {at: 0.5, expect: 'translateX(100px) rotate3d(1, 1, 0, 45deg) translateX(150px)'},
+  {at: 0.75, expect: 'translateX(100px) rotate3d(1, 1, 0, 45deg) translateX(175px)'},
+  {at: 1, expect: 'translateX(100px) rotate3d(1, 1, 0, 45deg) translateX(200px)'},
+  {at: 1.5, expect: 'translateX(100px) rotate3d(1, 1, 0, 45deg) translateX(250px)'},
+]);
+
+// Addition of non-invertible matrices is still defined as concatenation so
+// includes the underlying value.
+
+test_composition({
+  property: 'transform',
+  // Non-invertible.
+  underlying: 'matrix(1, 1, 0, 0, 0, 100)',
+  // translateX(100px)
+  addFrom: 'matrix(1, 0, 0, 1, 100, 0)',
+  // translateX(200px)
+  addTo: 'matrix(1, 0, 0, 1, 200, 0)',
+}, [
+  {at: -0.5, expect: 'matrix(1, 1, 0, 0, 100, 200)'},
+  {at: 0, expect: 'matrix(1, 1, 0, 0, 100, 200)'},
+  {at: 0.25, expect: 'matrix(1, 1, 0, 0, 100, 200)'},
+  {at: 0.5, expect: 'matrix(1, 1, 0, 0, 200, 300)'},
+  {at: 0.75, expect: 'matrix(1, 1, 0, 0, 200, 300)'},
+  {at: 1, expect: 'matrix(1, 1, 0, 0, 200, 300)'},
+  {at: 1.5, expect: 'matrix(1, 1, 0, 0, 200, 300)'},
+]);
+
+test_composition({
+  property: 'transform',
+  // translateX(100px)
+  underlying: 'matrix(1, 0, 0, 1, 100, 0)',
+  // Non-invertible
+  addFrom: 'matrix(1, 1, 0, 0, 0, 100)',
+  // translateX(200px)
+  addTo: 'matrix(1, 0, 0, 1, 200, 0)',
+}, [
+  {at: -0.5, expect: 'matrix(1, 1, 0, 0, 100, 100)'},
+  {at: 0, expect: 'matrix(1, 1, 0, 0, 100, 100)'},
+  {at: 0.25, expect: 'matrix(1, 1, 0, 0, 100, 100)'},
+  {at: 0.5, expect: 'matrix(1, 0, 0, 1, 300, 0)'},
+  {at: 0.75, expect: 'matrix(1, 0, 0, 1, 300, 0)'},
+  {at: 1, expect: 'matrix(1, 0, 0, 1, 300, 0)'},
+  {at: 1.5, expect: 'matrix(1, 0, 0, 1, 300, 0)'},
+]);
+
+// ------------ Accumulation tests --------------
+
+test_composition({
+  property: 'transform',
+  // translateX(100px) rotate(90deg)
+  underlying: 'matrix(0, 1, -1, 0, 100, 0)',
+  // translateX(100px)
+  accumulateFrom: 'matrix(1, 0, 0, 1, 100, 0)',
+  // translateX(200px)
+  accumulateTo: 'matrix(1, 0, 0, 1, 200, 0)',
+}, [
+  {at: -0.5, expect: 'matrix(0, 1, -1, 0, 150, 0)'},
+  {at: 0, expect: 'matrix(0, 1, -1, 0, 200, 0)'},
+  {at: 0.25, expect: 'matrix(0, 1, -1, 0, 225, 0)'},
+  {at: 0.5, expect: 'matrix(0, 1, -1, 0, 250, 0)'},
+  {at: 0.75, expect: 'matrix(0, 1, -1, 0, 275, 0)'},
+  {at: 1, expect: 'matrix(0, 1, -1, 0, 300, 0)'},
+  {at: 1.5, expect: 'matrix(0, 1, -1, 0, 350, 0)'},
+]);
+
+test_composition({
+  property: 'transform',
+  // translateX(100px) rotate3d(1, 1, 0, 45deg)
+  underlying: create3dMatrix(1, 1, 0, Math.PI / 4, 100),
+  // translateX(100px)
+  accumulateFrom: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 100, 0, 0, 1)',
+  // translateX(200px)
+  accumulateTo: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 200, 0, 0, 1)',
+}, [
+  // matrix3ds are hard to read; these are the decomposed forms for clarity
+  {at: -0.5, expect: 'translateX(150px) rotate3d(1, 1, 0, 45deg)'},
+  {at: 0, expect: 'translateX(200px) rotate3d(1, 1, 0, 45deg)'},
+  {at: 0.25, expect: 'translateX(225px) rotate3d(1, 1, 0, 45deg)'},
+  {at: 0.5, expect: 'translateX(250px) rotate3d(1, 1, 0, 45deg)'},
+  {at: 0.75, expect: 'translateX(275px) rotate3d(1, 1, 0, 45deg)'},
+  {at: 1, expect: 'translateX(300px) rotate3d(1, 1, 0, 45deg)'},
+  {at: 1.5, expect: 'translateX(350px) rotate3d(1, 1, 0, 45deg)'},
+]);
+
+// Accumulation of non-invertible matrices falls back to replace behavior.
+
+test_composition({
+  property: 'transform',
+  // Non-invertible.
+  underlying: 'matrix(1, 1, 0, 0, 0, 100)',
+  // translateX(100px)
+  accumulateFrom: 'matrix(1, 0, 0, 1, 100, 0)',
+  // translateX(200px)
+  accumulateTo: 'matrix(1, 0, 0, 1, 200, 0)',
+}, [
+  {at: -0.5, expect: 'matrix(1, 0, 0, 1, 50, 0)'},
+  {at: 0, expect: 'matrix(1, 0, 0, 1, 100, 0)'},
+  {at: 0.25, expect: 'matrix(1, 0, 0, 1, 125, 0)'},
+  {at: 0.5, expect: 'matrix(1, 0, 0, 1, 150, 0)'},
+  {at: 0.75, expect: 'matrix(1, 0, 0, 1, 175, 0)'},
+  {at: 1, expect: 'matrix(1, 0, 0, 1, 200, 0)'},
+  {at: 1.5, expect: 'matrix(1, 0, 0, 1, 250, 0)'},
+]);
+
+test_composition({
+  property: 'transform',
+  // translateX(100px)
+  underlying: 'matrix(1, 0, 0, 1, 100, 0)',
+  // Non-invertible
+  accumulateFrom: 'matrix(1, 1, 0, 0, 0, 100)',
+  // translateX(200px)
+  accumulateTo: 'matrix(1, 0, 0, 1, 200, 0)',
+}, [
+  {at: -0.5, expect: 'matrix(1, 1, 0, 0, 0, 100)'},
+  {at: 0, expect: 'matrix(1, 1, 0, 0, 0, 100)'},
+  {at: 0.25, expect: 'matrix(1, 1, 0, 0, 0, 100)'},
+  {at: 0.5, expect: 'matrix(1, 0, 0, 1, 300, 0)'},
+  {at: 0.75, expect: 'matrix(1, 0, 0, 1, 300, 0)'},
+  {at: 1, expect: 'matrix(1, 0, 0, 1, 300, 0)'},
+  {at: 1.5, expect: 'matrix(1, 0, 0, 1, 300, 0)'},
+]);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-perspective-composition.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-perspective-composition.html
new file mode 100644
index 0000000..82f8dad
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-perspective-composition.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>transform-perspective composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#three-d-transform-functions">
+<meta name="assert" content="transform-perspective supports animation as a transform list">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+// Addition and accumulation of perspective values are very similar, but not
+// identical. We can test the difference by constructing a scenario where a
+// perspective parameter would go negative in one case (and thus be clamped
+// to 0), and would not go negative in the other case.
+//
+// In the test below, the values differ at 1.5 progress. The reason for this
+// is that at 1.5 progress, the addition case (which uses concatenation)
+// computes to:
+//
+//   perspective(10px) perspective(-50px)
+//
+// Since perspective cannot go negative, this is clamped to:
+//
+//   perspective(10px) identity
+//
+// The accumulation case, on the other hand, combines the components
+// and so ends up blending from perspective(5px) to perspective(8.33...px) at
+// 1.5 progress, which results in perspective(12.5px) - this is what you would
+// get with addition too, if not for the clamping behavior.
+
+// ------------ Addition tests --------------
+
+test_composition({
+  property: 'transform',
+  underlying: 'perspective(10px)',
+  addFrom: 'perspective(10px)',
+  addTo: 'perspective(50px)',
+}, [
+  {at: -0.5, expect: 'perspective(4.12px)'},
+  {at: 0, expect: 'perspective(5px)'},
+  {at: 0.25, expect: 'perspective(5.45px)'},
+  {at: 0.5, expect: 'perspective(6.15px)'},
+  {at: 0.75, expect: 'perspective(7.06px)'},
+  {at: 1, expect: 'perspective(8.33px)'},
+  {at: 1.5, expect: 'perspective(10px)'},
+]);
+
+// ------------ Accumulation tests --------------
+
+test_composition({
+  property: 'transform',
+  underlying: 'perspective(10px)',
+  accumulateFrom: 'perspective(10px)',
+  accumulateTo: 'perspective(50px)',
+}, [
+  {at: -0.5, expect: 'perspective(4.12px)'},
+  {at: 0, expect: 'perspective(5px)'},
+  {at: 0.25, expect: 'perspective(5.45px)'},
+  {at: 0.5, expect: 'perspective(6.15px)'},
+  {at: 0.75, expect: 'perspective(7.06px)'},
+  {at: 1, expect: 'perspective(8.33px)'},
+  {at: 1.5, expect: 'perspective(12.5px)'},
+]);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-rotate-composition.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-rotate-composition.html
new file mode 100644
index 0000000..e062860
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-rotate-composition.html
@@ -0,0 +1,164 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>transform-rotate composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-transforms/#funcdef-transform-rotate">
+<meta name="assert" content="transform-rotate supports animation as a transform list">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+// ------------ Addition tests --------------
+
+test_composition({
+  property: 'transform',
+  underlying: 'rotateX(20deg)',
+  addFrom: 'rotateX(40deg)',
+  addTo: 'rotateX(60deg)',
+}, [
+  {at: -0.5, expect: 'rotateX(50deg)'},
+  {at: 0, expect: 'rotateX(60deg)'},
+  {at: 0.25, expect: 'rotateX(65deg)'},
+  {at: 0.5, expect: 'rotateX(70deg)'},
+  {at: 0.75, expect: 'rotateX(75deg)'},
+  {at: 1, expect: 'rotateX(80deg)'},
+  {at: 1.5, expect: 'rotateX(90deg)'},
+]);
+
+test_composition({
+  property: 'transform',
+  underlying: 'rotateY(20deg)',
+  addFrom: 'rotateY(40deg)',
+  addTo: 'rotateY(60deg)',
+}, [
+  {at: -0.5, expect: 'rotateY(50deg)'},
+  {at: 0, expect: 'rotateY(60deg)'},
+  {at: 0.25, expect: 'rotateY(65deg)'},
+  {at: 0.5, expect: 'rotateY(70deg)'},
+  {at: 0.75, expect: 'rotateY(75deg)'},
+  {at: 1, expect: 'rotateY(80deg)'},
+  {at: 1.5, expect: 'rotateY(90deg)'},
+]);
+
+test_composition({
+  property: 'transform',
+  underlying: 'rotateZ(20deg)',
+  addFrom: 'rotateZ(40deg)',
+  addTo: 'rotateZ(60deg)',
+}, [
+  {at: -0.5, expect: 'rotateZ(50deg)'},
+  {at: 0, expect: 'rotateZ(60deg)'},
+  {at: 0.25, expect: 'rotateZ(65deg)'},
+  {at: 0.5, expect: 'rotateZ(70deg)'},
+  {at: 0.75, expect: 'rotateZ(75deg)'},
+  {at: 1, expect: 'rotateZ(80deg)'},
+  {at: 1.5, expect: 'rotateZ(90deg)'},
+]);
+
+// When testing rotate functions in isolation, the additive and accumulation
+// behaviors are functionally identical. This test includes a skew to ensure
+// both methods are implemented; add should append the from/to after the skew.
+test_composition({
+  property: 'transform',
+  underlying: 'rotate(45deg) skew(10deg, 20deg)',
+  addFrom: 'rotate(45deg)',
+  addTo: 'rotate(225deg)',
+}, [
+  {at: -0.5, expect: 'rotate(45deg) skew(10deg, 20deg) rotate(-45deg)'},
+  {at: 0, expect: 'rotate(45deg) skew(10deg, 20deg) rotate(45deg)'},
+  {at: 0.25, expect: 'rotate(45deg) skew(10deg, 20deg) rotate(90deg)'},
+  {at: 0.5, expect: 'rotate(45deg) skew(10deg, 20deg) rotate(135deg)'},
+  {at: 0.75, expect: 'rotate(45deg) skew(10deg, 20deg) rotate(180deg)'},
+  {at: 1, expect: 'rotate(45deg) skew(10deg, 20deg) rotate(225deg)'},
+  {at: 1.5, expect: 'rotate(45deg) skew(10deg, 20deg) rotate(315deg)'},
+]);
+// ------------ Accumulation tests --------------
+
+test_composition({
+  property: 'transform',
+  underlying: 'rotateX(20deg)',
+  accumulateFrom: 'rotateX(40deg)',
+  accumulateTo: 'rotateX(60deg)',
+}, [
+  {at: -0.5, expect: 'rotateX(50deg)'},
+  {at: 0, expect: 'rotateX(60deg)'},
+  {at: 0.25, expect: 'rotateX(65deg)'},
+  {at: 0.5, expect: 'rotateX(70deg)'},
+  {at: 0.75, expect: 'rotateX(75deg)'},
+  {at: 1, expect: 'rotateX(80deg)'},
+  {at: 1.5, expect: 'rotateX(90deg)'},
+]);
+
+test_composition({
+  property: 'transform',
+  underlying: 'rotateY(20deg)',
+  accumulateFrom: 'rotateY(40deg)',
+  accumulateTo: 'rotateY(60deg)',
+}, [
+  {at: -0.5, expect: 'rotateY(50deg)'},
+  {at: 0, expect: 'rotateY(60deg)'},
+  {at: 0.25, expect: 'rotateY(65deg)'},
+  {at: 0.5, expect: 'rotateY(70deg)'},
+  {at: 0.75, expect: 'rotateY(75deg)'},
+  {at: 1, expect: 'rotateY(80deg)'},
+  {at: 1.5, expect: 'rotateY(90deg)'},
+]);
+
+test_composition({
+  property: 'transform',
+  underlying: 'rotateZ(20deg)',
+  accumulateFrom: 'rotateZ(40deg)',
+  accumulateTo: 'rotateZ(60deg)',
+}, [
+  {at: -0.5, expect: 'rotateZ(50deg)'},
+  {at: 0, expect: 'rotateZ(60deg)'},
+  {at: 0.25, expect: 'rotateZ(65deg)'},
+  {at: 0.5, expect: 'rotateZ(70deg)'},
+  {at: 0.75, expect: 'rotateZ(75deg)'},
+  {at: 1, expect: 'rotateZ(80deg)'},
+  {at: 1.5, expect: 'rotateZ(90deg)'},
+]);
+
+// The rotate functions all share the same primitive type (rotate3d), so can be
+// accumulated between. If primitive type matching is not properly being
+// performed, this test would likely fail with a fallback to replace behavior.
+test_composition({
+  property: 'transform',
+  underlying: 'rotateX(45deg)',
+  accumulateFrom: 'rotateY(30deg)',
+  accumulateTo: 'rotateY(70deg)',
+}, [
+  // Due to how rotation is accumulated (addition of underlying angles), the
+  // behavior is identical to concatenating the components. The expectations
+  // are expressed as concatenations for readability.
+  {at: -0.5, expect: 'rotateX(45deg) rotateY(10deg)'},
+  {at: 0, expect: 'rotateX(45deg) rotateY(30deg)'},
+  {at: 0.25, expect: 'rotateX(45deg) rotateY(40deg)'},
+  {at: 0.5, expect: 'rotateX(45deg) rotateY(50deg)'},
+  {at: 0.75, expect: 'rotateX(45deg) rotateY(60deg)'},
+  {at: 1, expect: 'rotateX(45deg) rotateY(70deg)'},
+  {at: 1.5, expect: 'rotateX(45deg) rotateY(90deg)'},
+]);
+
+// When testing rotate functions in isolation, the additive and accumulation
+// behaviors are functionally identical. This test includes a skew to ensure
+// both methods are implemented; accumulate should combine the rotate before
+// the skew.
+test_composition({
+  property: 'transform',
+  underlying: 'rotate(45deg) skew(10deg, 20deg)',
+  accumulateFrom: 'rotate(45deg)',
+  accumulateTo: 'rotate(225deg)',
+}, [
+  {at: -0.5, expect: 'rotate(0deg) skew(10deg, 20deg)'},
+  {at: 0, expect: 'rotate(90deg) skew(10deg, 20deg)'},
+  {at: 0.25, expect: 'rotate(135deg) skew(10deg, 20deg)'},
+  {at: 0.5, expect: 'rotate(180deg) skew(10deg, 20deg)'},
+  {at: 0.75, expect: 'rotate(225deg) skew(10deg, 20deg)'},
+  {at: 1, expect: 'rotate(270deg) skew(10deg, 20deg)'},
+  {at: 1.5, expect: 'rotate(360deg) skew(10deg, 20deg)'},
+]);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-scale-composition.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-scale-composition.html
new file mode 100644
index 0000000..87c33a8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-scale-composition.html
@@ -0,0 +1,129 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>transform-scale composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-transforms/#two-d-transform-functions">
+<meta name="assert" content="transform-scale supports animation as a transform list">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+// Addition (aka concatenation) of scale functions results in multiplying their
+// values (scale(2) scale(3) == scale(6)), whereas accumulation does a 1-based
+// sum of the components (accumulate(scale(2), scale(3)) == scale(2 + 3 - 1) ==
+// scale(4)).
+
+// ------------ Addition tests --------------
+
+test_composition({
+  property: 'transform',
+  underlying: 'scaleX(2)',
+  addFrom: 'scaleX(3)',
+  addTo: 'scaleX(4)',
+}, [
+  {at: -0.5, expect: 'scaleX(5)'},
+  {at: 0, expect: 'scaleX(6)'},
+  {at: 0.25, expect: 'scaleX(6.5)'},
+  {at: 0.5, expect: 'scaleX(7)'},
+  {at: 0.75, expect: 'scaleX(7.5)'},
+  {at: 1, expect: 'scaleX(8)'},
+  {at: 1.5, expect: 'scaleX(9)'},
+]);
+
+test_composition({
+  property: 'transform',
+  underlying: 'scaleY(2)',
+  addFrom: 'scaleY(3)',
+  addTo: 'scaleY(4)',
+}, [
+  {at: -0.5, expect: 'scaleY(5)'},
+  {at: 0, expect: 'scaleY(6)'},
+  {at: 0.25, expect: 'scaleY(6.5)'},
+  {at: 0.5, expect: 'scaleY(7)'},
+  {at: 0.75, expect: 'scaleY(7.5)'},
+  {at: 1, expect: 'scaleY(8)'},
+  {at: 1.5, expect: 'scaleY(9)'},
+]);
+
+test_composition({
+  property: 'transform',
+  underlying: 'scaleZ(2)',
+  addFrom: 'scaleZ(3)',
+  addTo: 'scaleZ(4)',
+}, [
+  {at: -0.5, expect: 'scaleZ(5)'},
+  {at: 0, expect: 'scaleZ(6)'},
+  {at: 0.25, expect: 'scaleZ(6.5)'},
+  {at: 0.5, expect: 'scaleZ(7)'},
+  {at: 0.75, expect: 'scaleZ(7.5)'},
+  {at: 1, expect: 'scaleZ(8)'},
+  {at: 1.5, expect: 'scaleZ(9)'},
+]);
+
+// ------------ Accumulation tests --------------
+
+test_composition({
+  property: 'transform',
+  underlying: 'scaleX(2)',
+  accumulateFrom: 'scaleX(3)',
+  accumulateTo: 'scaleX(4)',
+}, [
+  {at: -0.5, expect: 'scaleX(3.5)'},
+  {at: 0, expect: 'scaleX(4)'},
+  {at: 0.25, expect: 'scaleX(4.25)'},
+  {at: 0.5, expect: 'scaleX(4.5)'},
+  {at: 0.75, expect: 'scaleX(4.75)'},
+  {at: 1, expect: 'scaleX(5)'},
+  {at: 1.5, expect: 'scaleX(5.5)'},
+]);
+
+test_composition({
+  property: 'transform',
+  underlying: 'scaleY(2)',
+  accumulateFrom: 'scaleY(3)',
+  accumulateTo: 'scaleY(4)',
+}, [
+  {at: -0.5, expect: 'scaleY(3.5)'},
+  {at: 0, expect: 'scaleY(4)'},
+  {at: 0.25, expect: 'scaleY(4.25)'},
+  {at: 0.5, expect: 'scaleY(4.5)'},
+  {at: 0.75, expect: 'scaleY(4.75)'},
+  {at: 1, expect: 'scaleY(5)'},
+  {at: 1.5, expect: 'scaleY(5.5)'},
+]);
+
+test_composition({
+  property: 'transform',
+  underlying: 'scaleZ(2)',
+  accumulateFrom: 'scaleZ(3)',
+  accumulateTo: 'scaleZ(4)',
+}, [
+  {at: -0.5, expect: 'scaleZ(3.5)'},
+  {at: 0, expect: 'scaleZ(4)'},
+  {at: 0.25, expect: 'scaleZ(4.25)'},
+  {at: 0.5, expect: 'scaleZ(4.5)'},
+  {at: 0.75, expect: 'scaleZ(4.75)'},
+  {at: 1, expect: 'scaleZ(5)'},
+  {at: 1.5, expect: 'scaleZ(5.5)'},
+]);
+
+// The scale functions all share the same primitive type (scale3d), so can be
+// accumulated between.
+test_composition({
+  property: 'transform',
+  underlying: 'scale(2, 4)',
+  accumulateFrom: 'scaleZ(3)',
+  accumulateTo: 'scaleZ(4)',
+}, [
+  {at: -0.5, expect: 'scale3d(2, 4, 2.5)'},
+  {at: 0, expect: 'scale3d(2, 4, 3)'},
+  {at: 0.25, expect: 'scale3d(2, 4, 3.25)'},
+  {at: 0.5, expect: 'scale3d(2, 4, 3.5)'},
+  {at: 0.75, expect: 'scale3d(2, 4, 3.75)'},
+  {at: 1, expect: 'scale3d(2, 4, 4)'},
+  {at: 1.5, expect: 'scale3d(2, 4, 4.5)'},
+]);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-skew-composition.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-skew-composition.html
new file mode 100644
index 0000000..cda44b6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-skew-composition.html
@@ -0,0 +1,124 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>transform-skew composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-transforms/#two-d-transform-functions">
+<meta name="assert" content="transform-skew supports animation as a transform list">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+// Addition (aka concatenation) of two skew functions skew(a) and skew(b)
+// results in computing tan(a) + tan(b), whereas accumulation results in summing
+// the components to get tan(a + b).
+
+// ------------ Addition tests --------------
+
+test_composition({
+  property: 'transform',
+  underlying: 'skewX(10deg)',
+  addFrom: 'skewX(30deg)',
+  addTo: 'skewX(50deg)',
+}, [
+  {at: -0.5, expect: 'skewX(10deg) skewX(20deg)'},
+  {at: 0, expect: 'skewX(10deg) skewX(30deg)'},
+  {at: 0.25, expect: 'skewX(10deg) skewX(35deg)'},
+  {at: 0.5, expect: 'skewX(10deg) skewX(40deg)'},
+  {at: 0.75, expect: 'skewX(10deg) skewX(45deg)'},
+  {at: 1, expect: 'skewX(10deg) skewX(50deg)'},
+  {at: 1.5, expect: 'skewX(10deg) skewX(60deg)'},
+]);
+
+test_composition({
+  property: 'transform',
+  underlying: 'skewY(10deg)',
+  addFrom: 'skewY(30deg)',
+  addTo: 'skewY(50deg)',
+}, [
+  {at: -0.5, expect: 'skewY(10deg) skewY(20deg)'},
+  {at: 0, expect: 'skewY(10deg) skewY(30deg)'},
+  {at: 0.25, expect: 'skewY(10deg) skewY(35deg)'},
+  {at: 0.5, expect: 'skewY(10deg) skewY(40deg)'},
+  {at: 0.75, expect: 'skewY(10deg) skewY(45deg)'},
+  {at: 1, expect: 'skewY(10deg) skewY(50deg)'},
+  {at: 1.5, expect: 'skewY(10deg) skewY(60deg)'},
+]);
+
+test_composition({
+  property: 'transform',
+  underlying: 'skew(10deg, 20deg)',
+  addFrom: 'skew(30deg, 10deg)',
+  addTo: 'skew(50deg, 50deg)',
+}, [
+  {at: -0.5, expect: 'skew(10deg, 20deg) skew(20deg, -10deg)'},
+  {at: 0, expect: 'skew(10deg, 20deg) skew(30deg, 10deg)'},
+  {at: 0.25, expect: 'skew(10deg, 20deg) skew(35deg, 20deg)'},
+  {at: 0.5, expect: 'skew(10deg, 20deg) skew(40deg, 30deg)'},
+  {at: 0.75, expect: 'skew(10deg, 20deg) skew(45deg, 40deg)'},
+  {at: 1, expect: 'skew(10deg, 20deg) skew(50deg, 50deg)'},
+  {at: 1.5, expect: 'skew(10deg, 20deg) skew(60deg, 70deg)'},
+]);
+
+// ------------ Accumulation tests --------------
+
+test_composition({
+  property: 'transform',
+  underlying: 'skewX(45deg)',
+  accumulateFrom: 'skewX(30deg)',
+  accumulateTo: 'skewX(70deg)',
+}, [
+  {at: -0.5, expect: 'skewX(55deg)'},
+  {at: 0, expect: 'skewX(75deg)'},
+  {at: 0.25, expect: 'skewX(85deg)'},
+  {at: 0.5, expect: 'skewX(95deg)'},
+  {at: 0.75, expect: 'skewX(105deg)'},
+  {at: 1, expect: 'skewX(115deg)'},
+  {at: 1.5, expect: 'skewX(135deg)'},
+]);
+
+test_composition({
+  property: 'transform',
+  underlying: 'skewY(45deg)',
+  accumulateFrom: 'skewY(30deg)',
+  accumulateTo: 'skewY(70deg)',
+}, [
+  {at: -0.5, expect: 'skewY(55deg)'},
+  {at: 0, expect: 'skewY(75deg)'},
+  {at: 0.25, expect: 'skewY(85deg)'},
+  {at: 0.5, expect: 'skewY(95deg)'},
+  {at: 0.75, expect: 'skewY(105deg)'},
+  {at: 1, expect: 'skewY(115deg)'},
+  {at: 1.5, expect: 'skewY(135deg)'},
+]);
+
+test_composition({
+  property: 'transform',
+  underlying: 'skew(10deg, 45deg)',
+  accumulateFrom: 'skew(20deg, 30deg)',
+  accumulateTo: 'skew(40deg, 70deg)',
+}, [
+  {at: -0.5, expect: 'skew(20deg, 55deg)'},
+  {at: 0, expect: 'skew(30deg, 75deg)'},
+  {at: 0.25, expect: 'skew(35deg, 85deg)'},
+  {at: 0.5, expect: 'skew(40deg, 95deg)'},
+  {at: 0.75, expect: 'skew(45deg, 105deg)'},
+  {at: 1, expect: 'skew(50deg, 115deg)'},
+  {at: 1.5, expect: 'skew(60deg, 135deg)'},
+]);
+
+// The skew{X,Y} functions DO NOT share the same primitive type, so cannot be
+// accumlated between directly. Instead, they fall back to matrix accumulation,
+// which this tests for.
+test_composition({
+  property: 'transform',
+  underlying: 'skewX(45deg)',
+  accumulateFrom: 'skewY(45deg)',
+  accumulateTo: 'skewY(45deg)',
+}, [
+  // Note that this is not equivalent to any form of combined skews.
+  {at: 0.5, expect: 'matrix(1, 1, 0.5, 1.5, 0, 0)'},
+]);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-translate-composition.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-translate-composition.html
new file mode 100644
index 0000000..49214c4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/transform-translate-composition.html
@@ -0,0 +1,147 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>transform-translate composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-transforms/#two-d-transform-functions">
+<meta name="assert" content="transform-translate supports animation as a transform list">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script src="../interpolation/resources/interpolation-test.js"></script>
+<script>
+// ------------ Addition tests --------------
+
+test_composition({
+  property: 'transform',
+  underlying: 'translate(10px, 20px)',
+  addFrom: 'translate(100px, 200px)',
+  addTo: 'translate(200px, 400px)',
+}, [
+  {at: -0.5, expect: 'translate(60px, 120px)'},
+  {at: 0, expect: 'translate(110px, 220px)'},
+  {at: 0.25, expect: 'translate(135px, 270px)'},
+  {at: 0.5, expect: 'translate(160px, 320px)'},
+  {at: 0.75, expect: 'translate(185px, 370px)'},
+  {at: 1, expect: 'translate(210px, 420px)'},
+  {at: 1.5, expect: 'translate(260px, 520px)'},
+]);
+
+test_composition({
+  property: 'transform',
+  underlying: 'translate(10px, 20px)',
+  addFrom: 'translate(100px, 200px)',
+  replaceTo: 'translate(210px, 420px)',
+}, [
+  {at: -0.5, expect: 'translate(60px, 120px)'},
+  {at: 0, expect: 'translate(110px, 220px)'},
+  {at: 0.25, expect: 'translate(135px, 270px)'},
+  {at: 0.5, expect: 'translate(160px, 320px)'},
+  {at: 0.75, expect: 'translate(185px, 370px)'},
+  {at: 1, expect: 'translate(210px, 420px)'},
+  {at: 1.5, expect: 'translate(260px, 520px)'},
+]);
+
+// When testing translate functions in isolation, the additive and accumulation
+// behaviors are functionally identical. This test includes a rotate to ensure
+// both methods are implemented; add should append the from/to after the rotate.
+test_composition({
+  property: 'transform',
+  underlying: 'translateX(100px) rotate(90deg)',
+  addFrom: 'translateX(100px)',
+  addTo: 'translateX(200px)',
+}, [
+  {at: -0.5, expect: 'translateX(100px) rotate(90deg) translateX(50px)'},
+  {at: 0, expect: 'translateX(100px) rotate(90deg) translateX(100px)'},
+  {at: 0.25, expect: 'translateX(100px) rotate(90deg) translateX(125px)'},
+  {at: 0.5, expect: 'translateX(100px) rotate(90deg) translateX(150px)'},
+  {at: 0.75, expect: 'translateX(100px) rotate(90deg) translateX(175px)'},
+  {at: 1, expect: 'translateX(100px) rotate(90deg) translateX(200px)'},
+  {at: 1.5, expect: 'translateX(100px) rotate(90deg) translateX(250px)'},
+]);
+
+// ------------ Accumulation tests --------------
+
+test_composition({
+  property: 'transform',
+  underlying: 'translateX(100px)',
+  accumulateFrom: 'translateX(50px)',
+  accumulateTo: 'translateX(250px)',
+}, [
+  {at: -0.5, expect: 'translateX(50px)'},
+  {at: 0, expect: 'translateX(150px)'},
+  {at: 0.25, expect: 'translateX(200px)'},
+  {at: 0.5, expect: 'translateX(250px)'},
+  {at: 0.75, expect: 'translateX(300px)'},
+  {at: 1, expect: 'translateX(350px)'},
+  {at: 1.5, expect: 'translateX(450px)'},
+]);
+
+test_composition({
+  property: 'transform',
+  underlying: 'translateY(100px)',
+  accumulateFrom: 'translateY(50px)',
+  accumulateTo: 'translateY(250px)',
+}, [
+  {at: -0.5, expect: 'translateY(50px)'},
+  {at: 0, expect: 'translateY(150px)'},
+  {at: 0.25, expect: 'translateY(200px)'},
+  {at: 0.5, expect: 'translateY(250px)'},
+  {at: 0.75, expect: 'translateY(300px)'},
+  {at: 1, expect: 'translateY(350px)'},
+  {at: 1.5, expect: 'translateY(450px)'},
+]);
+
+test_composition({
+  property: 'transform',
+  underlying: 'translateZ(100px)',
+  accumulateFrom: 'translateZ(50px)',
+  accumulateTo: 'translateZ(250px)',
+}, [
+  {at: -0.5, expect: 'translateZ(50px)'},
+  {at: 0, expect: 'translateZ(150px)'},
+  {at: 0.25, expect: 'translateZ(200px)'},
+  {at: 0.5, expect: 'translateZ(250px)'},
+  {at: 0.75, expect: 'translateZ(300px)'},
+  {at: 1, expect: 'translateZ(350px)'},
+  {at: 1.5, expect: 'translateZ(450px)'},
+]);
+
+// The translate functions all share the same primitive type (translate3d), so
+// can be accumulated between.
+test_composition({
+  property: 'transform',
+  underlying: 'translate(100px, 50px)',
+  accumulateFrom: 'translateZ(50px)',
+  accumulateTo: 'translateZ(250px)',
+}, [
+  {at: -0.5, expect: 'translate3d(100px, 50px, -50px)'},
+  {at: 0, expect: 'translate3d(100px, 50px, 50px)'},
+  {at: 0.25, expect: 'translate3d(100px, 50px, 100px)'},
+  {at: 0.5, expect: 'translate3d(100px, 50px, 150px)'},
+  {at: 0.75, expect: 'translate3d(100px, 50px, 200px)'},
+  {at: 1, expect: 'translate3d(100px, 50px, 250px)'},
+  {at: 1.5, expect: 'translate3d(100px, 50px, 350px)'},
+]);
+
+// When testing translate functions in isolation, the additive and accumulation
+// behaviors are functionally identical. This test includes a rotate to ensure
+// both methods are implemented; accumulate should combine the transform before
+// the rotate.
+test_composition({
+  property: 'transform',
+  underlying: 'translateX(100px) rotate(90deg)',
+  accumulateFrom: 'translateX(100px)',
+  accumulateTo: 'translateX(200px)',
+}, [
+  {at: -0.5, expect: 'translateX(150px) rotate(90deg)'},
+  {at: 0, expect: 'translateX(200px) rotate(90deg)'},
+  {at: 0.25, expect: 'translateX(225px) rotate(90deg)'},
+  {at: 0.5, expect: 'translateX(250px) rotate(90deg)'},
+  {at: 0.75, expect: 'translateX(275px) rotate(90deg)'},
+  {at: 1, expect: 'translateX(300px) rotate(90deg)'},
+  {at: 1.5, expect: 'translateX(350px) rotate(90deg)'},
+]);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/translate-composition.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/translate-composition.html
new file mode 100644
index 0000000..3abdb45
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/translate-composition.html
@@ -0,0 +1,147 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>translate composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#propdef-translate">
+<meta name="assert" content="translate supports <length> and <percentage> animation.">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<style>
+.target {
+  width: 100px;
+  height: 100px;
+}
+</style>
+<script>
+test_composition({
+  property: 'translate',
+  underlying: '100px 200px 300px',
+  addFrom: '-50px 50%',
+  addTo: '100%',
+}, [
+  {at: -1, expect: '-100% calc(200px + 100%) 300px'},
+  {at: 0, expect: 'calc(50px + 0%) calc(200px + 50%) 300px'},
+  {at: 0.25, expect: 'calc(62.5px + 25%) calc(200px + 37.5%) 300px'},
+  {at: 0.75, expect: 'calc(87.5px + 75%) calc(200px + 12.5%) 300px'},
+  {at: 1, expect: 'calc(100px + 100%) calc(200px + 0%) 300px'},
+  {at: 2, expect: 'calc(150px + 200%) calc(200px - 50%) 300px'},
+]);
+
+test_composition({
+  property: 'translate',
+  underlying: '100px 200px 300px',
+  addFrom: '50% 100px',
+  replaceTo: '200px 50% 100px',
+}, [
+  {at: -1, expect: '100% calc(600px - 50%) 500px'},
+  {at: 0, expect: 'calc(100px + 50%) calc(300px + 0%) 300px'},
+  {at: 0.25, expect: 'calc(125px + 37.5%) calc(225px + 12.5%) 250px'},
+  {at: 0.75, expect: 'calc(175px + 12.5%) calc(75px + 37.5%) 150px'},
+  {at: 1, expect: 'calc(200px + 0%) 50% 100px'},
+  {at: 2, expect: 'calc(300px - 50%) calc(-300px + 100%) -100px'},
+]);
+
+test_composition({
+  property: 'translate',
+  underlying: '100px 200px 300px',
+  replaceFrom: '50% 100px',
+  addTo: '200px 50% 100px',
+}, [
+  {at: -1, expect: 'calc(-300px + 100%) -50% -400px'},
+  {at: 0, expect: '50%  calc(100px + 0%)'},
+  {at: 0.25, expect: 'calc(75px + 37.5%) calc(125px + 12.5%) 100px'},
+  {at: 0.75, expect: 'calc(225px + 12.5%) calc(175px + 37.5%) 300px'},
+  {at: 1, expect: 'calc(300px + 0%) calc(200px + 50%) 400px'},
+  {at: 2, expect: 'calc(600px - 50%) calc(300px + 100%) 800px'},
+]);
+
+test_composition({
+  property: 'translate',
+  underlying: 'none',
+  replaceFrom: 'none',
+  addTo: '100px',
+}, [
+  {at: -1, expect: '-100px'},
+  {at: 0, expect: 'none'},
+  {at: 0.25, expect: '25px'},
+  {at: 0.75, expect: '75px'},
+  {at: 1, expect: '100px'},
+  {at: 2, expect: '200px'},
+]);
+
+test_composition({
+  property: 'translate',
+  underlying: 'none',
+  addFrom: 'none',
+  addTo: '100px',
+}, [
+  {at: -1, expect: '-100px'},
+  {at: 0, expect: 'none'},
+  {at: 0.25, expect: '25px'},
+  {at: 0.75, expect: '75px'},
+  {at: 1, expect: '100px'},
+  {at: 2, expect: '200px'},
+]);
+
+test_composition({
+  property: 'translate',
+  underlying: 'none',
+  replaceFrom: '0px 40px 60px',
+  replaceTo: 'none',
+}, [
+  {at: -1, expect: '0px 80px 120px'},
+  {at: 0, expect: '0px 40px 60px'},
+  {at: 0.25, expect: '0px 30px 45px'},
+  {at: 0.75, expect: '0px 10px 15px'},
+  {at: 1, expect: 'none'},
+  {at: 2, expect: '0px -40px -60px'},
+]);
+
+test_composition({
+  property: 'translate',
+  underlying: 'none',
+  replaceFrom: '0px 40px 60px',
+  addTo: 'none',
+}, [
+  {at: -1, expect: '0px 80px 120px'},
+  {at: 0, expect: '0px 40px 60px'},
+  {at: 0.25, expect: '0px 30px 45px'},
+  {at: 0.75, expect: '0px 10px 15px'},
+  {at: 1, expect: 'none'},
+  {at: 2, expect: '0px -40px -60px'},
+]);
+
+test_composition({
+  property: 'translate',
+  underlying: '80px 20px',
+  addFrom: 'none',
+  replaceTo: '0px 40px 60px',
+}, [
+  {at: -1, expect: '160px 0px -60px'},
+  {at: 0, expect: '80px 20px'},
+  {at: 0.25, expect: '60px 25px 15px'},
+  {at: 0.5, expect: '40px 30px 30px'},
+  {at: 0.75, expect: '20px 35px 45px'},
+  {at: 1, expect: '0px 40px 60px'},
+  {at: 2, expect: '-80px 60px 120px'},
+]);
+
+test_composition({
+  property: 'translate',
+  underlying: '80px 20px',
+  addFrom: '0px 40px 60px',
+  replaceTo: 'none',
+}, [
+  {at: -1, expect: '160px 120px 120px'},
+  {at: 0, expect: '80px 60px 60px'},
+  {at: 0.25, expect: '60px 45px 45px'},
+  {at: 0.5, expect: '40px 30px 30px'},
+  {at: 0.75, expect: '20px 15px 15px'},
+  {at: 1, expect: 'none'},
+  {at: 2, expect: '-80px -60px -60px'},
+]);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/animations/vertical-align-composition.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/animations/vertical-align-composition.html
new file mode 100644
index 0000000..222a511
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/animations/vertical-align-composition.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>vertical-align composition</title>
+<link rel="help" href="https://www.w3.org/TR/CSS2/visudet.html#propdef-vertical-align">
+<meta name="assert" content="vertical-align supports animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+  property: 'vertical-align',
+  underlying: '50px',
+  addFrom: '100px',
+  addTo: '200px',
+}, [
+  {at: -0.3, expect: '120px'},
+  {at: 0, expect: '150px'},
+  {at: 0.5, expect: '200px'},
+  {at: 1, expect: '250px'},
+  {at: 1.5, expect: '300px'},
+]);
+
+test_composition({
+  property: 'vertical-align',
+  underlying: '100px',
+  addFrom: '10px',
+  addTo: '2px',
+}, [
+  {at: -0.5, expect: '114px'},
+  {at: 0, expect: '110px'},
+  {at: 0.5, expect: '106px'},
+  {at: 1, expect: '102px'},
+  {at: 1.5, expect: '98px'},
+]);
+
+test_composition({
+  property: 'vertical-align',
+  underlying: '10%',
+  addFrom: '100px',
+  addTo: '20%',
+}, [
+  {at: -0.3, expect: 'calc(130px + 4%)'},
+  {at: 0, expect: 'calc(100px + 10%)'},
+  {at: 0.5, expect: 'calc(50px + 20%)'},
+  {at: 1, expect: '30%'},
+  {at: 1.5, expect: 'calc(-50px + 40%)'},
+]);
+
+test_composition({
+  property: 'vertical-align',
+  underlying: '50px',
+  addFrom: '100px',
+  replaceTo: '200px',
+}, [
+  {at: -0.3, expect: '135px'},
+  {at: 0, expect: '150px'},
+  {at: 0.5, expect: '175px'},
+  {at: 1, expect: '200px'},
+  {at: 1.5, expect: '225px'},
+]);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini
index c6f136d..87726f4 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini
@@ -1,4 +1,6 @@
 [allowed-to-play.html]
+  disabled:
+    if product == "firefox": https://bugzilla.mozilla.org/show_bug.cgi?id=1607802
   expected:
     if product == "safari": ERROR # https://bugs.webkit.org/show_bug.cgi?id=190775
 
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/DOMParser-parseFromString-regression.tentative.https.html b/third_party/blink/web_tests/external/wpt/trusted-types/DOMParser-parseFromString-regression.tentative.https.html
new file mode 100644
index 0000000..30986e45
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/DOMParser-parseFromString-regression.tentative.https.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta http-equiv="Content-Security-Policy" content="blabla">
+<body>
+<div id="target"></div>
+<div id="probe"></div>
+<script>
+test(t => {
+  // Regression test for crbug.com/1030830. (Should work in any browser, though.)
+  //
+  // The top-level doc has a CSP that doesn't do anything interesting. We'll
+  // parse a doc and create an iframe with an embedded CSP, and will ensure that
+  // the CSP applies to the frame, but not the top-level doc.
+  const target = document.getElementById("target");
+  const probe = document.getElementById("probe");
+  probe.innerHTML = "probe";
+
+  const doc = new DOMParser().parseFromString(`
+    <meta http-equiv="Content-Security-Policy" content="trusted-types *">
+    <body><div id="probe"></div></body>"`, "text/html");
+  probe.innerHTML = "probe";
+
+  const frame = document.createElement("iframe");
+  frame.src = `data:text/html;${encodeURI(doc.documentElement.outerHTML)}`;
+  frame.id = "frame";
+  target.appendChild(frame);
+  const frame_probe = document.getElementById("frame").contentDocument.getElementById("probe");
+  probe.innerHTML = "probe";
+  assert_throws(new TypeError(), _ => { frame_probe.innnerHTML = "probe" });
+}, "Regression test for TT changes to parseFromString.");
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-createHTMLDocument.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-createHTMLDocument.tentative-expected.txt
deleted file mode 100644
index 000dc2b..0000000
--- a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-createHTMLDocument.tentative-expected.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-This is a testharness.js-based test.
-PASS Trusted Type assignment is blocked. (document)
-PASS Trusted Type instances created in the main doc can be used. (document)
-PASS Trusted Type assignment is blocked. (createHTMLDocument)
-PASS Trusted Type instances created in the main doc can be used. (createHTMLDocument)
-FAIL Trusted Type assignment is blocked. (DOMParser) assert_throws: function "_ => { doc.createElement("script").textContent = "2+2"; }" did not throw
-FAIL Trusted Type instances created in the main doc can be used. (DOMParser) assert_throws: function "_ => { doc.body.innerHTML = "world"; }" did not throw
-PASS Trusted Type assignment is blocked. (XHR)
-PASS Trusted Type instances created in the main doc can be used. (XHR)
-PASS Install default policy.
-PASS Default policy applies. (document)
-PASS Default policy applies. (createHTMLDocument)
-PASS Default policy applies. (DOMParser)
-PASS Default policy applies. (XHR)
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/fast/forms/date/input-date-validation-message-expected.txt b/third_party/blink/web_tests/fast/forms/date/input-date-validation-message-expected.txt
index 996cf8e..d07cc02 100644
--- a/third_party/blink/web_tests/fast/forms/date/input-date-validation-message-expected.txt
+++ b/third_party/blink/web_tests/fast/forms/date/input-date-validation-message-expected.txt
@@ -9,6 +9,8 @@
 PASS testIt("", "", "") is "Please fill out this field."
 Type mismatch
 PASS testIt("foo", "", "") is ""
+Range invalid
+PASS testIt("1990-05-29", "1990-05-30", "1990-05-28") is "Minimum date (05/30/1990) must come before Maximum date (05/28/1990)."
 Range overflow
 PASS testIt("1982-11-02", "", "1970-12-31") is "Value must be 12/31/1970 or earlier."
 Range underflow
diff --git a/third_party/blink/web_tests/fast/forms/date/input-date-validation-message.html b/third_party/blink/web_tests/fast/forms/date/input-date-validation-message.html
index a88bd3ca7..cd7cb97 100644
--- a/third_party/blink/web_tests/fast/forms/date/input-date-validation-message.html
+++ b/third_party/blink/web_tests/fast/forms/date/input-date-validation-message.html
@@ -32,6 +32,9 @@
 debug('Type mismatch');
 shouldBeEqualToString('testIt("foo", "", "")', '');
 
+debug('Range invalid')
+shouldBeEqualToString('testIt("1990-05-29", "1990-05-30", "1990-05-28")', 'Minimum date (05/30/1990) must come before Maximum date (05/28/1990).');
+
 debug('Range overflow')
 shouldBeEqualToString('testIt("1982-11-02", "", "1970-12-31")', 'Value must be 12/31/1970 or earlier.');
 
diff --git a/third_party/blink/web_tests/fast/forms/resources/picker-common.js b/third_party/blink/web_tests/fast/forms/resources/picker-common.js
index 9444002..8db456d 100644
--- a/third_party/blink/web_tests/fast/forms/resources/picker-common.js
+++ b/third_party/blink/web_tests/fast/forms/resources/picker-common.js
@@ -11,8 +11,8 @@
     setTimeout(popupOpenCallback, 20);
 }
 
-function waitUntilClosing(callback) {
-    setTimeout(callback, 1);
+function waitUntilClosing(callback, customDelay) {
+    setTimeout(callback, (customDelay !== undefined) ? customDelay : 1);
 }
 
 function rootWindow() {
@@ -34,34 +34,6 @@
 // - INPUT color with DATALIST
 // - INPUT date/datetime-local/month/week
 function openPicker(element, callback, errorCallback) {
-    popupWindow = openPickerHelper(element);
-    if (typeof callback === "function" && popupWindow)
-        setPopupOpenCallback(callback);
-    else if (typeof errorCallback === "function" && !popupWindow)
-        errorCallback();
-}
-
-// openPickerWithPromise opens a picker UI for the following types:
-// - menulist SELECT
-// - INPUT color
-// - INPUT date/datetime-local/month/week
-//
-// Returns a Promise that resolves when the popup has been opened.
-function openPickerWithPromise(element) {
-    return new Promise(function(resolve, reject) {
-        popupWindow = openPickerHelper(element);
-        if (popupWindow) {
-            popupWindow.addEventListener("didOpenPicker", resolve, false);
-        } else {
-            reject();
-        }
-    });
-}
-
-// Helper function for openPicker and openPickerWithPromise.
-// Performs the keystrokes that will cause the picker to open,
-// and returns the popup window, or null.
-function openPickerHelper(element) {
     element.offsetTop; // Force to lay out
     element.focus();
     if (element.tagName === "SELECT") {
@@ -73,7 +45,11 @@
             eventSender.keyDown("ArrowDown", ["altKey"]);
         }
     }
-    return internals.pagePopupWindow;
+    popupWindow = internals.pagePopupWindow;
+    if (typeof callback === "function" && popupWindow)
+        setPopupOpenCallback(callback);
+    else if (typeof errorCallback === "function" && !popupWindow)
+        errorCallback();
 }
 
 function clickToOpenPicker(x, y, callback, errorCallback) {
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/color/color-picker-appearance-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/color/color-picker-appearance-expected.png
index 0506476..3700a096 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/color/color-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/color/color-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/color/color-picker-appearance-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/color/color-picker-appearance-expected.png
index d76ad62..103fc646 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/color/color-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/color/color-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-click-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-click-expected.png
index 472b7cbb..513826a7 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-click-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-click-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-down-keyboard-navigation-from-top-left-corner-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-down-keyboard-navigation-from-top-left-corner-expected.png
index 2777e5e..7d3cd3b 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-down-keyboard-navigation-from-top-left-corner-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-down-keyboard-navigation-from-top-left-corner-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-down-keyboard-navigation-from-top-right-corner-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-down-keyboard-navigation-from-top-right-corner-expected.png
index 3a771b5..782ffd67 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-down-keyboard-navigation-from-top-right-corner-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-down-keyboard-navigation-from-top-right-corner-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-drag-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-drag-expected.png
index 472b7cbb..513826a7 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-drag-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-drag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-keyboard-navigation-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-keyboard-navigation-expected.png
index d7224dd..5afd3ef 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-keyboard-navigation-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-keyboard-navigation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-left-keyboard-navigation-from-bottom-right-corner-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-left-keyboard-navigation-from-bottom-right-corner-expected.png
index d4c7f47..7a25036 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-left-keyboard-navigation-from-bottom-right-corner-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-left-keyboard-navigation-from-bottom-right-corner-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-left-keyboard-navigation-from-top-right-corner-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-left-keyboard-navigation-from-top-right-corner-expected.png
index 8dc58ec..c2e5b5a 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-left-keyboard-navigation-from-top-right-corner-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-left-keyboard-navigation-from-top-right-corner-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-right-keyboard-navigation-from-bottom-left-corner-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-right-keyboard-navigation-from-bottom-left-corner-expected.png
index 8380ffd7..9376492 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-right-keyboard-navigation-from-bottom-left-corner-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-right-keyboard-navigation-from-bottom-left-corner-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-right-keyboard-navigation-from-top-left-corner-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-right-keyboard-navigation-from-top-left-corner-expected.png
index 236fb85..7d69248 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-right-keyboard-navigation-from-top-left-corner-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-right-keyboard-navigation-from-top-left-corner-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-up-keyboard-navigation-from-bottom-left-corner-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-up-keyboard-navigation-from-bottom-left-corner-expected.png
index 4d7a46a..3053c524 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-up-keyboard-navigation-from-bottom-left-corner-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-up-keyboard-navigation-from-bottom-left-corner-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-up-keyboard-navigation-from-bottom-right-corner-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-up-keyboard-navigation-from-bottom-right-corner-expected.png
index b2b9877..2dbe819c 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-up-keyboard-navigation-from-bottom-right-corner-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-color-well-up-keyboard-navigation-from-bottom-right-corner-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hex-format-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hex-format-expected.png
index 2266fbee..701399db 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hex-format-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hex-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hsl-format-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hsl-format-expected.png
index 1331ff29..8c38887 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hsl-format-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hsl-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-accelerated-keyboard-navigation-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-accelerated-keyboard-navigation-expected.png
index 8b06bcf..7b30bdb 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-accelerated-keyboard-navigation-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-accelerated-keyboard-navigation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-click-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-click-expected.png
index 2bf6e04b..b3072285 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-click-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-click-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-drag-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-drag-expected.png
index 2bf6e04b..b3072285 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-drag-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-drag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-keyboard-navigation-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-keyboard-navigation-expected.png
index 307468f7..0e60d0e6a 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-keyboard-navigation-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-keyboard-navigation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
index f3dd485..4789f2a 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
index 130d9bc..7fbc4d3 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-imperfect-match-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-imperfect-match-expected.png
index 896918f..2f3017d5 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-imperfect-match-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-imperfect-match-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-manual-color-change-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-manual-color-change-expected.png
index cd8e63ea..7263ab6 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-manual-color-change-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-manual-color-change-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-set-value-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-set-value-expected.png
index 6acfe9c3..0faa811 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-set-value-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-set-value-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-value-attribute-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-value-attribute-expected.png
index b4d50022..16d1491 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-value-attribute-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-value-attribute-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-zoom125-expected.png
index 1ae83c7..91efffd 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-zoom200-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-zoom200-expected.png
index 9ea95f9..e9f0823 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-zoom200-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color/color-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/color/color-picker-appearance-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/color/color-picker-appearance-expected.png
index 53e7683..39becea09 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/color/color-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/color/color-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/color/color-picker-appearance-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/color/color-picker-appearance-expected.png
index d3c96b03..2727347ca 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/color/color-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/color/color-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-click-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-click-expected.png
index e96b861..bb943ed 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-click-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-click-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-down-keyboard-navigation-from-top-left-corner-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-down-keyboard-navigation-from-top-left-corner-expected.png
index 92f8ebe..0393f9d 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-down-keyboard-navigation-from-top-left-corner-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-down-keyboard-navigation-from-top-left-corner-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-down-keyboard-navigation-from-top-right-corner-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-down-keyboard-navigation-from-top-right-corner-expected.png
index 6776ef2..090a8c6 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-down-keyboard-navigation-from-top-right-corner-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-down-keyboard-navigation-from-top-right-corner-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-drag-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-drag-expected.png
index e96b861..bb943ed 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-drag-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-drag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-keyboard-navigation-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-keyboard-navigation-expected.png
index f0644fe..2a681ea 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-keyboard-navigation-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-keyboard-navigation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-left-keyboard-navigation-from-bottom-right-corner-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-left-keyboard-navigation-from-bottom-right-corner-expected.png
index 3f4655f..f78fec6 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-left-keyboard-navigation-from-bottom-right-corner-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-left-keyboard-navigation-from-bottom-right-corner-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-left-keyboard-navigation-from-top-right-corner-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-left-keyboard-navigation-from-top-right-corner-expected.png
index 4dfe404..599c090 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-left-keyboard-navigation-from-top-right-corner-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-left-keyboard-navigation-from-top-right-corner-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-right-keyboard-navigation-from-bottom-left-corner-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-right-keyboard-navigation-from-bottom-left-corner-expected.png
index 5e43cb4..e587ded 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-right-keyboard-navigation-from-bottom-left-corner-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-right-keyboard-navigation-from-bottom-left-corner-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-right-keyboard-navigation-from-top-left-corner-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-right-keyboard-navigation-from-top-left-corner-expected.png
index 9dbfbbd..8af1519d 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-right-keyboard-navigation-from-top-left-corner-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-right-keyboard-navigation-from-top-left-corner-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-up-keyboard-navigation-from-bottom-left-corner-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-up-keyboard-navigation-from-bottom-left-corner-expected.png
index 2a47431..b2792dd 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-up-keyboard-navigation-from-bottom-left-corner-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-up-keyboard-navigation-from-bottom-left-corner-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-up-keyboard-navigation-from-bottom-right-corner-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-up-keyboard-navigation-from-bottom-right-corner-expected.png
index 6bd37a8c..0afe6028 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-up-keyboard-navigation-from-bottom-right-corner-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-color-well-up-keyboard-navigation-from-bottom-right-corner-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hex-format-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hex-format-expected.png
index 5e07307..a453c44 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hex-format-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hex-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hsl-format-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hsl-format-expected.png
index 1e6b80ff..77a9a66 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hsl-format-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hsl-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-accelerated-keyboard-navigation-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-accelerated-keyboard-navigation-expected.png
index 85ffe05..337eb82 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-accelerated-keyboard-navigation-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-accelerated-keyboard-navigation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-click-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-click-expected.png
index c959607d..d7a19a4 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-click-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-click-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-drag-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-drag-expected.png
index c959607d..d7a19a4 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-drag-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-drag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-keyboard-navigation-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-keyboard-navigation-expected.png
index 758ce17..98b5324 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-keyboard-navigation-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-keyboard-navigation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
index dbf011f4..ff4b7b44 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
index 47407a4..500ab54f 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-imperfect-match-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-imperfect-match-expected.png
index 6b94fb1..c3305767 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-imperfect-match-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-imperfect-match-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-manual-color-change-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-manual-color-change-expected.png
index b985cc1..cbc0181 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-manual-color-change-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-manual-color-change-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-set-value-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-set-value-expected.png
index 87be1f6..82ae927 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-set-value-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-set-value-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-value-attribute-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-value-attribute-expected.png
index f989b7a..77f76f7 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-value-attribute-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-value-attribute-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-zoom125-expected.png
index edbf519b..06e0ff9 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-zoom200-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-zoom200-expected.png
index c8f313e..3515be60 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-zoom200-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color/color-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/color/color-picker-enter-submission.html b/third_party/blink/web_tests/virtual/controls-refresh/color/color-picker-enter-submission.html
new file mode 100644
index 0000000..b6e958f
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/controls-refresh/color/color-picker-enter-submission.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src='../../../resources/testharness.js'></script>
+<script src='../../../resources/testharnessreport.js'></script>
+<script src='../../../fast/forms/resources/picker-common.js'></script>
+</head>
+<body>
+<input type='color' id='color' value='#80d9ff'>
+<script>
+'use strict';
+
+let t = async_test('Color picker: Pressing enter to submit color selection.');
+t.step(() => {
+  let colorControl = document.getElementById('color');
+  openPicker(colorControl, t.step_func(() => {
+    popupWindow.focus();
+    const popupDocument = popupWindow.document;
+    const colorWell = popupDocument.querySelector('color-well');
+    const colorWellRect = colorWell.getBoundingClientRect();
+    eventSender.mouseMoveTo(colorWellRect.left, colorWellRect.top);
+    eventSender.mouseDown();
+    eventSender.mouseMoveTo(colorWellRect.left + (colorWellRect.width * 4 / 10), colorWellRect.top + (colorWellRect.height * 6 / 10));
+    eventSender.mouseUp();
+    eventSender.keyDown('Enter');
+    waitUntilClosing(t.step_func_done(() => {
+      assert_equals(colorControl.value, '#3d5a66', 'Color control value should update after pressing enter.');
+    }), popupWindow.eval('ColorPicker').COMMIT_DELAY_MS);
+  }), t.step_func_done(() => {
+    assert_true(true, 'Popup did not open.');
+  }));
+});
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/color/color-picker-escape-cancellation.html b/third_party/blink/web_tests/virtual/controls-refresh/color/color-picker-escape-cancellation.html
index 5a4549b5..85543c53 100644
--- a/third_party/blink/web_tests/virtual/controls-refresh/color/color-picker-escape-cancellation.html
+++ b/third_party/blink/web_tests/virtual/controls-refresh/color/color-picker-escape-cancellation.html
@@ -6,124 +6,30 @@
 <script src='../../../fast/forms/resources/picker-common.js'></script>
 </head>
 <body>
-<input type='color' id='color1' value='#80d9ff'>
-<input type='color' id='color2' value='#3d5a66'>
-<input type='color' id='color3' value='#000000'>
+<input type='color' id='color' value='#80d9ff'>
 <script>
 'use strict';
 
-promise_test(() => {
-  let colorControl = document.getElementById('color1');
-  return openPickerWithPromise(colorControl)
-  .then(() => {
-    internals.pagePopupWindow.focus();
-    eventSender.keyDown('Escape');
-    assert_equals(internals.pagePopupWindow, null, 'Popup should close after pressing escape with no changes.');
-  });
-}, "Color picker: Pressing escape with no changes should close the popup");
-
-promise_test(() => {
-  let colorControl = document.getElementById('color1');
-  return openPickerWithPromise(colorControl)
-  .then(() => {
-    internals.pagePopupWindow.focus();
-    const popupDocument = internals.pagePopupWindow.document;
+let t = async_test('Color picker: Pressing escape to discard color selection.');
+t.step(() => {
+  let colorControl = document.getElementById('color');
+  openPicker(colorControl, t.step_func(() => {
+    popupWindow.focus();
+    const popupDocument = popupWindow.document;
     const colorWell = popupDocument.querySelector('color-well');
     const colorWellRect = colorWell.getBoundingClientRect();
     eventSender.mouseMoveTo(colorWellRect.left, colorWellRect.top);
     eventSender.mouseDown();
     eventSender.mouseMoveTo(colorWellRect.left + (colorWellRect.width * 4 / 10), colorWellRect.top + (colorWellRect.height * 6 / 10));
     eventSender.mouseUp();
-    assert_equals(colorControl.value, '#3d5a66', 'Expected color value to change from mouse input.');
     eventSender.keyDown('Escape');
-    assert_equals(colorControl.value, '#80d9ff', 'Color control value should have reverted back after pressing escape.');
-    assert_not_equals(internals.pagePopupWindow, null, 'Popup should still be open after escape that reverted color value.');
-    eventSender.keyDown('Escape');
-    assert_equals(internals.pagePopupWindow, null, 'Popup should close after second escape.');
-  });
-}, "Color picker: Pressing escape once discards color selection but keeps popup open, pressing again closes popup");
-
-promise_test(() => {
-  let colorControl = document.getElementById('color1');
-  return openPickerWithPromise(colorControl)
-  .then(() => {
-    internals.pagePopupWindow.focus();
-    const popupDocument = internals.pagePopupWindow.document;
-    const colorWell = popupDocument.querySelector('color-well');
-    const rValueContainer = popupDocument.getElementById('rValueContainer');
-    const rValueContainerRect = rValueContainer.getBoundingClientRect();
-    eventSender.mouseMoveTo(rValueContainerRect.left + 1, rValueContainerRect.top);
-    eventSender.mouseDown();
-    eventSender.mouseUp();
-    assert_equals(rValueContainer.value, '128');
-    eventSender.keyDown('Delete');
-    assert_equals(rValueContainer.value, '28');
-    assert_equals(colorControl.value, '#1cd9ff', 'Expected color value to change from manualinput.');
-    eventSender.keyDown('Escape');
-    assert_equals(colorControl.value, '#80d9ff', 'Color control value should have reverted back after pressing escape.');
-    assert_equals(rValueContainer.value, '128');
-    assert_not_equals(internals.pagePopupWindow, null, 'Popup should still be open after escape that reverted color value.');
-    eventSender.keyDown('Escape');
-    assert_equals(internals.pagePopupWindow, null, 'Popup should close after second escape.');
-  });
-}, "Color picker: Pressing escape once discards manual color selection but keeps popup open, pressing again closes popup");
-
-promise_test(() => {
-  let colorControl = document.getElementById('color2');
-  return openPickerWithPromise(colorControl)
-  .then(() => {
-    internals.pagePopupWindow.focus();
-    const popupDocument = internals.pagePopupWindow.document;
-    const colorWell = popupDocument.querySelector('color-well');
-    const colorWellRect = colorWell.getBoundingClientRect();
-    eventSender.mouseMoveTo(colorWellRect.left + (colorWellRect.width * 2 / 10), colorWellRect.top + (colorWellRect.height * 3 / 10));
-    eventSender.mouseDown();
-    eventSender.mouseUp();
-    assert_equals(colorControl.value, '#8fa8b3', 'Mouse input should have changed color value.');
-
-    eventSender.mouseMoveTo(colorWellRect.left + (colorWellRect.width * 4 / 10), colorWellRect.top + (colorWellRect.height * 6 / 10));
-    eventSender.mouseDown();
-    eventSender.mouseUp();
-    assert_equals(colorControl.value, '#3d5a66', 'Mouse input should have changed color back to original value.');
-    eventSender.keyDown('Escape');
-    assert_equals(internals.pagePopupWindow, null, 'Single escape should change popup since its value was switched back the value when opened');
-  });
-}, "Color picker: Pressing escape closes popup after value is changed and then set back to original value.");
-
-promise_test(() => {
-  let colorControl = document.getElementById('color3');
-  return openPickerWithPromise(colorControl)
-  .then(() => {
-    internals.pagePopupWindow.focus();
-    const popupDocument = internals.pagePopupWindow.document;
-    const hueSlider = popupDocument.querySelector('hue-slider');
-    const hueSliderRect = hueSlider.getBoundingClientRect();
-    eventSender.mouseMoveTo(hueSliderRect.left, hueSliderRect.top);
-    eventSender.mouseDown();
-    eventSender.mouseMoveTo(hueSliderRect.left + (hueSliderRect.width / 2), hueSliderRect.top);
-    eventSender.mouseUp();
-    assert_equals(colorControl.value, '#000000', 'Hue slider should not have changed value when starting from #000000.');
-
-    eventSender.keyDown('Escape');
-    assert_equals(internals.pagePopupWindow, null, 'Single escape should close popup if hue slider but not color value changed');
-  });
-}, "Color picker: Hue slider change with no color value change doesn't affect escape behavior");
-
-promise_test(() => {
-  let colorControl = document.getElementById('color3');
-  return openPickerWithPromise(colorControl)
-  .then(() => {
-    internals.pagePopupWindow.focus();
-    const popupDocument = internals.pagePopupWindow.document;
-    const formatToggler = popupDocument.querySelector('format-toggler');
-    formatToggler.click();  // first click changes format to HSL
-    formatToggler.click();  // second click changes format to Hex
-
-    eventSender.keyDown('Escape');
-    assert_equals(internals.pagePopupWindow, null, 'Single escape should close popup if manual color entry format but not color value changed');
-  });
-}, "Color picker: Format changes with no color value change don't affect escape behavior");
-
+    waitUntilClosing(t.step_func_done(() => {
+      assert_equals(colorControl.value, '#80d9ff', 'Color control value should remain the same after pressing escape.');
+    }), popupWindow.eval('ColorPicker').COMMIT_DELAY_MS);
+  }), t.step_func_done(() => {
+    assert_true(true, 'Popup did not open.');
+  }));
+});
 </script>
 </body>
 </html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/color/color-picker-events.html b/third_party/blink/web_tests/virtual/controls-refresh/color/color-picker-events.html
deleted file mode 100644
index 8209532..0000000
--- a/third_party/blink/web_tests/virtual/controls-refresh/color/color-picker-events.html
+++ /dev/null
@@ -1,103 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src='../../../resources/testharness.js'></script>
-<script src='../../../resources/testharnessreport.js'></script>
-<script src='../../../fast/forms/resources/picker-common.js'></script>
-</head>
-<body>
-<input type='color' id='color1' value='#000000' oninput='inputEventCount++;' onchange='changeEventCount++;'>
-<script>
-'use strict';
-
-var inputEventCount = 0;
-var changeEventCount = 0;
-
-promise_test(() => {
-  let colorControl = document.getElementById('color1');
-  return openPickerWithPromise(colorControl)
-  .then(() => {
-    internals.pagePopupWindow.focus();
-    eventSender.keyDown('Enter');
-    assert_equals(inputEventCount, 0, 'No input event should have fired if color value was not changed.');
-    return new Promise((resolve) => {
-      window.setTimeout(() => {
-        assert_equals(changeEventCount, 0, 'No change event should have fired if color value was not changed.');
-        resolve();
-      }, 0)
-    });
-  });
-}, "Color picker: Opening and closing popup with no changes should not fire input/change events");
-
-promise_test(() => {
-  inputEventCount = 0;
-  changeEventCount = 0;
-  let colorControl = document.getElementById('color1');
-  return openPickerWithPromise(colorControl)
-  .then(() => {
-    internals.pagePopupWindow.focus();
-    const popupDocument = internals.pagePopupWindow.document;
-    const rValueContainer = popupDocument.getElementById('rValueContainer');
-    rValueContainer.focus();
-
-    assert_equals(rValueContainer.value, '0');
-    eventSender.keyDown('1');
-    assert_equals(rValueContainer.value, '01');
-    assert_equals(inputEventCount, 1, 'Input event should have fired after color value change.');
-    assert_equals(changeEventCount, 0, 'No change event should have fired before popup is closed.');
-
-    eventSender.keyDown('2');
-    assert_equals(rValueContainer.value, '012');
-    assert_equals(inputEventCount, 2, 'Additional input event should have fired after additional color value change.');
-    assert_equals(changeEventCount, 0, 'No change event should have fired before popup is closed.');
-    
-    eventSender.keyDown('Enter');
-    assert_equals(internals.pagePopupWindow, null, "Popup should have closed from Enter key");
-    assert_equals(inputEventCount, 2, 'No extra input event should fire when closing popup.');
-    assert_equals(changeEventCount, 0, 'Change event is fired asynchronously after closing popup.');
-    return new Promise((resolve) => {
-      window.setTimeout(() => {
-        assert_equals(changeEventCount, 1, 'Change event should have fired (once) asynchronously after closing popup.');
-        resolve();
-      }, 0)
-    });
-  });
-}, "Color picker: Test firing change and input events");
-
-promise_test(() => {
-  inputEventCount = 0;
-  changeEventCount = 0;
-  let colorControl = document.getElementById('color1');
-  colorControl.value = '#000000';
-  return openPickerWithPromise(colorControl)
-  .then(() => {
-    internals.pagePopupWindow.focus();
-    const popupDocument = internals.pagePopupWindow.document;
-    const rValueContainer = popupDocument.getElementById('rValueContainer');
-    rValueContainer.focus();
-
-    assert_equals(rValueContainer.value, '0');
-    eventSender.keyDown('1');
-    assert_equals(rValueContainer.value, '01');
-    assert_equals(inputEventCount, 1, 'Input event should have fired after color value change.');
-    assert_equals(changeEventCount, 0, 'No change event should have fired before popup is closed.');
-    
-    eventSender.keyDown('Escape');
-    assert_equals(rValueContainer.value, '0');
-    assert_equals(inputEventCount, 2, 'Additional input event should have fired after color value is reset.');
-    assert_equals(changeEventCount, 0, 'No change event should have fired before popup is closed.');
-    
-    eventSender.keyDown('Enter');
-    assert_equals(internals.pagePopupWindow, null, "Popup should have closed from Enter key");
-    assert_equals(inputEventCount, 2, 'No extra input event should fire when closing popup.');
-    return new Promise((resolve) => {
-      window.setTimeout(() => {
-        assert_equals(changeEventCount, 0, 'Change event should not fire if value when opening popup is restored.');
-        resolve();
-      }, 0)
-    });
-  });
-}, "Color picker: Test that change is not fired if original value is restored");
-</script>
-</body>
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/color/color-picker-tab-navigation-expected.txt b/third_party/blink/web_tests/virtual/controls-refresh/color/color-picker-tab-navigation-expected.txt
index ebad46c..4fe22dc 100644
--- a/third_party/blink/web_tests/virtual/controls-refresh/color/color-picker-tab-navigation-expected.txt
+++ b/third_party/blink/web_tests/virtual/controls-refresh/color/color-picker-tab-navigation-expected.txt
@@ -5,7 +5,11 @@
 GVALUECONTAINER
 BVALUECONTAINER
 FORMAT-TOGGLER
+SUBMISSION-BUTTON
+SUBMISSION-BUTTON
 FORMAT-TOGGLER clicked. Active color format changed.
+SUBMISSION-BUTTON
+SUBMISSION-BUTTON
 COLOR-SELECTION-RING
 COLOR-SELECTION-RING
 HVALUECONTAINER
@@ -13,6 +17,8 @@
 LVALUECONTAINER
 FORMAT-TOGGLER
 FORMAT-TOGGLER clicked. Active color format changed.
+SUBMISSION-BUTTON
+SUBMISSION-BUTTON
 COLOR-SELECTION-RING
 COLOR-SELECTION-RING
 HEXVALUECONTAINER
diff --git a/third_party/dav1d/config/linux-noasm/x64/config.h b/third_party/dav1d/config/linux-noasm/x64/config.h
index 92a2bd8..3a667d0 100644
--- a/third_party/dav1d/config/linux-noasm/x64/config.h
+++ b/third_party/dav1d/config/linux-noasm/x64/config.h
@@ -29,8 +29,6 @@
 
 #define HAVE_CLOCK_GETTIME 1
 
-#define HAVE_DLSYM 1
-
 #define HAVE_POSIX_MEMALIGN 1
 
 #define HAVE_UNISTD_H 1
diff --git a/third_party/dav1d/config/linux/arm/config.h b/third_party/dav1d/config/linux/arm/config.h
index 7d2cfa2..1bda003 100644
--- a/third_party/dav1d/config/linux/arm/config.h
+++ b/third_party/dav1d/config/linux/arm/config.h
@@ -31,8 +31,6 @@
 
 #define HAVE_CLOCK_GETTIME 1
 
-#define HAVE_DLSYM 1
-
 #define HAVE_GETAUXVAL 1
 
 #define HAVE_POSIX_MEMALIGN 1
diff --git a/third_party/dav1d/config/linux/arm64/config.h b/third_party/dav1d/config/linux/arm64/config.h
index 603edd8..3f0339a 100644
--- a/third_party/dav1d/config/linux/arm64/config.h
+++ b/third_party/dav1d/config/linux/arm64/config.h
@@ -31,8 +31,6 @@
 
 #define HAVE_CLOCK_GETTIME 1
 
-#define HAVE_DLSYM 1
-
 #define HAVE_GETAUXVAL 1
 
 #define HAVE_POSIX_MEMALIGN 1
diff --git a/third_party/dav1d/config/linux/x64/config.h b/third_party/dav1d/config/linux/x64/config.h
index a088a06f..fc2a07b 100644
--- a/third_party/dav1d/config/linux/x64/config.h
+++ b/third_party/dav1d/config/linux/x64/config.h
@@ -29,8 +29,6 @@
 
 #define HAVE_CLOCK_GETTIME 1
 
-#define HAVE_DLSYM 1
-
 #define HAVE_POSIX_MEMALIGN 1
 
 #define HAVE_UNISTD_H 1
diff --git a/third_party/dav1d/config/linux/x86/config.h b/third_party/dav1d/config/linux/x86/config.h
index 972ec8a..123524a 100644
--- a/third_party/dav1d/config/linux/x86/config.h
+++ b/third_party/dav1d/config/linux/x86/config.h
@@ -29,8 +29,6 @@
 
 #define HAVE_CLOCK_GETTIME 1
 
-#define HAVE_DLSYM 1
-
 #define HAVE_POSIX_MEMALIGN 1
 
 #define HAVE_UNISTD_H 1
diff --git a/third_party/dav1d/dav1d_generated.gni b/third_party/dav1d/dav1d_generated.gni
index e32f0e4..e5c6fda3 100644
--- a/third_party/dav1d/dav1d_generated.gni
+++ b/third_party/dav1d/dav1d_generated.gni
@@ -1,4 +1,4 @@
-# Copyright 2020 The Chromium Authors. All rights reserved.
+# 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.
 
@@ -102,8 +102,6 @@
   "libdav1d/src/ipred.h",
   "libdav1d/src/ipred_prepare.h",
   "libdav1d/src/itx.h",
-  "libdav1d/src/itx_1d.c",
-  "libdav1d/src/itx_1d.h",
   "libdav1d/src/levels.h",
   "libdav1d/src/lf_apply.h",
   "libdav1d/src/lf_mask.c",
diff --git a/third_party/dav1d/generate_source.py b/third_party/dav1d/generate_source.py
index 9ab5e00..0ca1c55 100755
--- a/third_party/dav1d/generate_source.py
+++ b/third_party/dav1d/generate_source.py
@@ -26,6 +26,9 @@
     "libdav1d/src/thread_task.h",
 ]
 
+# .c files which are included by other .c files and shouldn't be listed.
+DAV1D_C_FILE_INCLUDES = ["libdav1d/src/itx_1d.c"]
+
 
 def WriteArray(fd, var_name, array, filter_list=[], last_entry=False):
   if len(array) == 0:
@@ -56,8 +59,9 @@
 
   # Generate list of sources which need to be compiled multiple times with the
   # correct -DBIT_DEPTH=8|10 option specified each time.
-  WriteArray(fd, "c_sources", glob.glob("libdav1d/src/*.[c|h]"),
-             DAV1D_ENTRY_POINT_SOURCES + template_sources)
+  WriteArray(
+      fd, "c_sources", glob.glob("libdav1d/src/*.[c|h]"),
+      DAV1D_ENTRY_POINT_SOURCES + DAV1D_C_FILE_INCLUDES + template_sources)
 
   WriteArray(
       fd, "entry_point_sources", DAV1D_ENTRY_POINT_SOURCES, last_entry=True)
diff --git a/third_party/protobuf/proto_library.gni b/third_party/protobuf/proto_library.gni
index aeaa6c5d..3591b53b 100644
--- a/third_party/protobuf/proto_library.gni
+++ b/third_party/protobuf/proto_library.gni
@@ -473,8 +473,8 @@
 #     args = [
 #       "--encode=foo.FooMessage",
 #       "-I",
-#       rebase_path("//component/core"),
-#       "foo.proto",
+#       rebase_path("//"),
+#       "component/core/foo.proto",
 #     ]
 #   }
 template("protoc_convert") {
diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn
index 5f88733..9d0f021f 100644
--- a/third_party/zlib/BUILD.gn
+++ b/third_party/zlib/BUILD.gn
@@ -29,9 +29,12 @@
 config("zlib_adler32_simd_config") {
   if (use_x86_x64_optimizations) {
     defines = [ "ADLER32_SIMD_SSSE3" ]
-  }
-
-  if (use_arm_neon_optimizations) {
+    if (is_win) {
+      defines += [ "X86_WINDOWS" ]
+    } else {
+      defines += [ "X86_NOT_WINDOWS" ]
+    }
+  } else if (use_arm_neon_optimizations) {
     defines = [ "ADLER32_SIMD_NEON" ]
   }
 }
@@ -94,24 +97,13 @@
     if (!is_ios) {
       include_dirs = [ "." ]
 
-      if (is_android) {
-        import("//build/config/android/config.gni")
-        if (defined(android_ndk_root) && android_ndk_root != "") {
-          deps = [
-            "//third_party/android_ndk:cpu_features",
-          ]
-        } else {
-          assert(false, "CPU detection requires the Android NDK")
-        }
-      } else if (!is_win && !is_clang) {
+      if (!is_win && !is_clang) {
         assert(!use_thin_lto,
                "ThinLTO fails mixing different module-level targets")
         cflags_c = [ "-march=armv8-a+crc" ]
       }
 
       sources = [
-        "arm_features.c",
-        "arm_features.h",
         "crc32_simd.c",
         "crc32_simd.h",
       ]
@@ -218,10 +210,6 @@
         "-mpclmul",
       ]
     }
-  } else {
-    sources = [
-      "simd_stub.c",
-    ]
   }
 
   configs -= [ "//build/config/compiler:chromium_code" ]
@@ -248,6 +236,8 @@
     "chromeconf.h",
     "compress.c",
     "contrib/optimizations/insert_string.h",
+    "cpu_features.c",
+    "cpu_features.h",
     "crc32.c",
     "crc32.h",
     "deflate.c",
@@ -267,7 +257,6 @@
     "trees.c",
     "trees.h",
     "uncompr.c",
-    "x86.h",
     "zconf.h",
     "zlib.h",
     "zutil.c",
@@ -276,6 +265,19 @@
 
   defines = []
   deps = []
+  if (!use_x86_x64_optimizations && !use_arm_neon_optimizations) {
+    # Apparently android_cronet bot builds with NEON disabled and
+    # we also should disable optimizations for iOS@x86 (a.k.a. simulator).
+    defines += [ "CPU_NO_SIMD" ]
+  }
+
+  if (is_ios) {
+    # iOS@ARM is a special case where we always have NEON but don't check
+    # for crypto extensions.
+    # TODO(cavalcantii): verify what is the current state of CPU features shipped
+    # on latest iOS devices.
+    defines += [ "ARM_OS_IOS" ]
+  }
 
   if (use_x86_x64_optimizations || use_arm_neon_optimizations) {
     deps += [
@@ -284,7 +286,6 @@
     ]
 
     if (use_x86_x64_optimizations) {
-      sources += [ "x86.c" ]
       deps += [ ":zlib_crc32_simd" ]
     } else if (use_arm_neon_optimizations) {
       sources += [ "contrib/optimizations/slide_hash_neon.h" ]
@@ -294,6 +295,15 @@
     sources += [ "inflate.c" ]
   }
 
+  if (is_android) {
+    import("//build/config/android/config.gni")
+    if (defined(android_ndk_root) && android_ndk_root != "") {
+      deps += [ "//third_party/android_ndk:cpu_features" ]
+    } else {
+      assert(false, "CPU detection requires the Android NDK")
+    }
+  }
+
   configs -= [ "//build/config/compiler:chromium_code" ]
   configs += [
     ":zlib_internal_config",
diff --git a/third_party/zlib/adler32.c b/third_party/zlib/adler32.c
index a42f35fc..696773a 100644
--- a/third_party/zlib/adler32.c
+++ b/third_party/zlib/adler32.c
@@ -59,10 +59,8 @@
 #  define MOD63(a) a %= BASE
 #endif
 
-#if defined(ADLER32_SIMD_SSSE3)
-#include "adler32_simd.h"
-#include "x86.h"
-#elif defined(ADLER32_SIMD_NEON)
+#include "cpu_features.h"
+#if defined(ADLER32_SIMD_SSSE3) || defined(ADLER32_SIMD_NEON)
 #include "adler32_simd.h"
 #endif
 
@@ -108,7 +106,7 @@
      */
     if (buf == Z_NULL) {
         if (!len) /* Assume user is calling adler32(0, NULL, 0); */
-            x86_check_features();
+            cpu_check_features();
         return 1L;
     }
 #else
diff --git a/third_party/zlib/arm_features.c b/third_party/zlib/arm_features.c
deleted file mode 100644
index f5641c3..0000000
--- a/third_party/zlib/arm_features.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/* arm_features.c -- ARM processor features detection.
- *
- * 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 Chromium source repository LICENSE file.
- */
-
-#include "arm_features.h"
-#include "zutil.h"
-#include <stdint.h>
-
-int ZLIB_INTERNAL arm_cpu_enable_crc32 = 0;
-int ZLIB_INTERNAL arm_cpu_enable_pmull = 0;
-
-#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_FUCHSIA)
-#include <pthread.h>
-#endif
-
-#if defined(ARMV8_OS_ANDROID)
-#include <cpu-features.h>
-#elif defined(ARMV8_OS_LINUX)
-#include <asm/hwcap.h>
-#include <sys/auxv.h>
-#elif defined(ARMV8_OS_FUCHSIA)
-#include <zircon/features.h>
-#include <zircon/syscalls.h>
-#include <zircon/types.h>
-#elif defined(ARMV8_OS_WINDOWS)
-#include <windows.h>
-#else
-#error arm_features.c ARM feature detection in not defined for your platform
-#endif
-
-static void _arm_check_features(void);
-
-#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_FUCHSIA)
-static pthread_once_t cpu_check_inited_once = PTHREAD_ONCE_INIT;
-void ZLIB_INTERNAL arm_check_features(void)
-{
-    pthread_once(&cpu_check_inited_once, _arm_check_features);
-}
-#elif defined(ARMV8_OS_WINDOWS)
-static INIT_ONCE cpu_check_inited_once = INIT_ONCE_STATIC_INIT;
-static BOOL CALLBACK _arm_check_features_forwarder(PINIT_ONCE once, PVOID param, PVOID* context)
-{
-    _arm_check_features();
-    return TRUE;
-}
-void ZLIB_INTERNAL arm_check_features(void)
-{
-    InitOnceExecuteOnce(&cpu_check_inited_once, _arm_check_features_forwarder,
-                        NULL, NULL);
-}
-#endif
-
-/*
- * See http://bit.ly/2CcoEsr for run-time detection of ARM features and also
- * crbug.com/931275 for android_getCpuFeatures() use in the Android sandbox.
- */
-static void _arm_check_features(void)
-{
-#if defined(ARMV8_OS_ANDROID) && defined(__aarch64__)
-    uint64_t features = android_getCpuFeatures();
-    arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM64_FEATURE_CRC32);
-    arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM64_FEATURE_PMULL);
-#elif defined(ARMV8_OS_ANDROID) /* aarch32 */
-    uint64_t features = android_getCpuFeatures();
-    arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM_FEATURE_CRC32);
-    arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM_FEATURE_PMULL);
-#elif defined(ARMV8_OS_LINUX) && defined(__aarch64__)
-    unsigned long features = getauxval(AT_HWCAP);
-    arm_cpu_enable_crc32 = !!(features & HWCAP_CRC32);
-    arm_cpu_enable_pmull = !!(features & HWCAP_PMULL);
-#elif defined(ARMV8_OS_LINUX) && (defined(__ARM_NEON) || defined(__ARM_NEON__))
-    /* Query HWCAP2 for ARMV8-A SoCs running in aarch32 mode */
-    unsigned long features = getauxval(AT_HWCAP2);
-    arm_cpu_enable_crc32 = !!(features & HWCAP2_CRC32);
-    arm_cpu_enable_pmull = !!(features & HWCAP2_PMULL);
-#elif defined(ARMV8_OS_FUCHSIA)
-    uint32_t features;
-    zx_status_t rc = zx_system_get_features(ZX_FEATURE_KIND_CPU, &features);
-    if (rc != ZX_OK || (features & ZX_ARM64_FEATURE_ISA_ASIMD) == 0)
-        return;  /* Report nothing if ASIMD(NEON) is missing */
-    arm_cpu_enable_crc32 = !!(features & ZX_ARM64_FEATURE_ISA_CRC32);
-    arm_cpu_enable_pmull = !!(features & ZX_ARM64_FEATURE_ISA_PMULL);
-#elif defined(ARMV8_OS_WINDOWS)
-    arm_cpu_enable_crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
-    arm_cpu_enable_pmull = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
-#endif
-}
diff --git a/third_party/zlib/arm_features.h b/third_party/zlib/arm_features.h
deleted file mode 100644
index 09fec25..0000000
--- a/third_party/zlib/arm_features.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* arm_features.h -- ARM processor features detection.
- *
- * 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 Chromium source repository LICENSE file.
- */
-
-#include "zlib.h"
-
-extern int arm_cpu_enable_crc32;
-extern int arm_cpu_enable_pmull;
-
-void arm_check_features(void);
diff --git a/third_party/zlib/contrib/optimizations/insert_string.h b/third_party/zlib/contrib/optimizations/insert_string.h
index 69eee3d..1826601 100644
--- a/third_party/zlib/contrib/optimizations/insert_string.h
+++ b/third_party/zlib/contrib/optimizations/insert_string.h
@@ -10,6 +10,7 @@
 #define INLINE inline
 #endif
 
+#include "cpu_features.h"
 /* Optimized insert_string block */
 #if defined(CRC32_SIMD_SSE42_PCLMUL) || defined(CRC32_ARMV8_CRC32)
 #define TARGET_CPU_WITH_CRC
@@ -25,7 +26,6 @@
   #define _cpu_crc32_u32 _mm_crc32_u32
 
 #elif defined(CRC32_ARMV8_CRC32)
-  #include "arm_features.h"
   #if defined(__clang__)
     #undef TARGET_CPU_WITH_CRC
     #define __crc32cw __builtin_arm_crc32cw
diff --git a/third_party/zlib/cpu_features.c b/third_party/zlib/cpu_features.c
new file mode 100644
index 0000000..8a25dd2
--- /dev/null
+++ b/third_party/zlib/cpu_features.c
@@ -0,0 +1,145 @@
+/* cpu_features.c -- Processor features detection.
+ *
+ * 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 Chromium source repository LICENSE file.
+ */
+
+#include "cpu_features.h"
+#include "zutil.h"
+
+#include <stdint.h>
+#if defined(_MSC_VER)
+#include <intrin.h>
+#elif defined(ADLER32_SIMD_SSSE3)
+#include <cpuid.h>
+#endif
+
+/* TODO(cavalcantii): remove checks for x86_flags on deflate.
+ */
+int ZLIB_INTERNAL arm_cpu_enable_crc32 = 0;
+int ZLIB_INTERNAL arm_cpu_enable_pmull = 0;
+int ZLIB_INTERNAL x86_cpu_enable_ssse3 = 0;
+int ZLIB_INTERNAL x86_cpu_enable_simd = 0;
+
+#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_FUCHSIA)
+#include <pthread.h>
+#endif
+
+#if defined(ARMV8_OS_ANDROID)
+#include <cpu-features.h>
+#elif defined(ARMV8_OS_LINUX)
+#include <asm/hwcap.h>
+#include <sys/auxv.h>
+#elif defined(ARMV8_OS_FUCHSIA)
+#include <zircon/features.h>
+#include <zircon/syscalls.h>
+#include <zircon/types.h>
+#elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
+#include <windows.h>
+#elif !defined(_MSC_VER)
+#include <pthread.h>
+#else
+#error cpu_features.c CPU feature detection in not defined for your platform
+#endif
+
+#if !defined(CPU_NO_SIMD) && !defined(ARM_OS_IOS)
+static void _cpu_check_features(void);
+#endif
+
+#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_FUCHSIA) || defined(X86_NOT_WINDOWS)
+static pthread_once_t cpu_check_inited_once = PTHREAD_ONCE_INIT;
+void ZLIB_INTERNAL cpu_check_features(void)
+{
+    pthread_once(&cpu_check_inited_once, _cpu_check_features);
+}
+#elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
+static INIT_ONCE cpu_check_inited_once = INIT_ONCE_STATIC_INIT;
+static BOOL CALLBACK _cpu_check_features_forwarder(PINIT_ONCE once, PVOID param, PVOID* context)
+{
+    _cpu_check_features();
+    return TRUE;
+}
+void ZLIB_INTERNAL cpu_check_features(void)
+{
+    InitOnceExecuteOnce(&cpu_check_inited_once, _cpu_check_features_forwarder,
+                        NULL, NULL);
+}
+#endif
+
+#if (defined(__ARM_NEON__) || defined(__ARM_NEON))
+/*
+ * iOS@ARM is a special case where we always have NEON but don't check
+ * for crypto extensions.
+ */
+#ifndef ARM_OS_IOS
+/*
+ * See http://bit.ly/2CcoEsr for run-time detection of ARM features and also
+ * crbug.com/931275 for android_getCpuFeatures() use in the Android sandbox.
+ */
+static void _cpu_check_features(void)
+{
+#if defined(ARMV8_OS_ANDROID) && defined(__aarch64__)
+    uint64_t features = android_getCpuFeatures();
+    arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM64_FEATURE_CRC32);
+    arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM64_FEATURE_PMULL);
+#elif defined(ARMV8_OS_ANDROID) /* aarch32 */
+    uint64_t features = android_getCpuFeatures();
+    arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM_FEATURE_CRC32);
+    arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM_FEATURE_PMULL);
+#elif defined(ARMV8_OS_LINUX) && defined(__aarch64__)
+    unsigned long features = getauxval(AT_HWCAP);
+    arm_cpu_enable_crc32 = !!(features & HWCAP_CRC32);
+    arm_cpu_enable_pmull = !!(features & HWCAP_PMULL);
+#elif defined(ARMV8_OS_LINUX) && (defined(__ARM_NEON) || defined(__ARM_NEON__))
+    /* Query HWCAP2 for ARMV8-A SoCs running in aarch32 mode */
+    unsigned long features = getauxval(AT_HWCAP2);
+    arm_cpu_enable_crc32 = !!(features & HWCAP2_CRC32);
+    arm_cpu_enable_pmull = !!(features & HWCAP2_PMULL);
+#elif defined(ARMV8_OS_FUCHSIA)
+    uint32_t features;
+    zx_status_t rc = zx_system_get_features(ZX_FEATURE_KIND_CPU, &features);
+    if (rc != ZX_OK || (features & ZX_ARM64_FEATURE_ISA_ASIMD) == 0)
+        return;  /* Report nothing if ASIMD(NEON) is missing */
+    arm_cpu_enable_crc32 = !!(features & ZX_ARM64_FEATURE_ISA_CRC32);
+    arm_cpu_enable_pmull = !!(features & ZX_ARM64_FEATURE_ISA_PMULL);
+#elif defined(ARMV8_OS_WINDOWS)
+    arm_cpu_enable_crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
+    arm_cpu_enable_pmull = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
+#endif
+}
+#endif
+#elif defined(X86_NOT_WINDOWS) || defined(X86_WINDOWS)
+/*
+ * iOS@x86 (i.e. emulator) is another special case where we disable
+ * SIMD optimizations.
+ */
+#ifndef CPU_NO_SIMD
+/* On x86 we simply use a instruction to check the CPU features.
+ * (i.e. CPUID).
+ */
+static void _cpu_check_features(void)
+{
+    int x86_cpu_has_sse2;
+    int x86_cpu_has_ssse3;
+    int x86_cpu_has_sse42;
+    int x86_cpu_has_pclmulqdq;
+    int abcd[4];
+#ifdef _MSC_VER
+    __cpuid(abcd, 1);
+#else
+    __cpuid(1, abcd[0], abcd[1], abcd[2], abcd[3]);
+#endif
+    x86_cpu_has_sse2 = abcd[3] & 0x4000000;
+    x86_cpu_has_ssse3 = abcd[2] & 0x000200;
+    x86_cpu_has_sse42 = abcd[2] & 0x100000;
+    x86_cpu_has_pclmulqdq = abcd[2] & 0x2;
+
+    x86_cpu_enable_ssse3 = x86_cpu_has_ssse3;
+
+    x86_cpu_enable_simd = x86_cpu_has_sse2 &&
+                          x86_cpu_has_sse42 &&
+                          x86_cpu_has_pclmulqdq;
+}
+#endif
+#endif
diff --git a/third_party/zlib/cpu_features.h b/third_party/zlib/cpu_features.h
new file mode 100644
index 0000000..2a4a7973
--- /dev/null
+++ b/third_party/zlib/cpu_features.h
@@ -0,0 +1,17 @@
+/* cpu_features.h -- Processor features detection.
+ *
+ * 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 Chromium source repository LICENSE file.
+ */
+
+#include "zlib.h"
+
+/* TODO(cavalcantii): remove checks for x86_flags on deflate.
+ */
+extern int arm_cpu_enable_crc32;
+extern int arm_cpu_enable_pmull;
+extern int x86_cpu_enable_ssse3;
+extern int x86_cpu_enable_simd;
+
+void cpu_check_features(void);
diff --git a/third_party/zlib/crc32.c b/third_party/zlib/crc32.c
index e95b908..bd696470 100644
--- a/third_party/zlib/crc32.c
+++ b/third_party/zlib/crc32.c
@@ -29,13 +29,10 @@
 #endif /* MAKECRCH */
 
 #include "deflate.h"
-#include "x86.h"
+#include "cpu_features.h"
 #include "zutil.h"      /* for STDC and FAR definitions */
 
-#if defined(CRC32_SIMD_SSE42_PCLMUL)
-#include "crc32_simd.h"
-#elif defined(CRC32_ARMV8_CRC32)
-#include "arm_features.h"
+#if defined(CRC32_SIMD_SSE42_PCLMUL) || defined(CRC32_ARMV8_CRC32)
 #include "crc32_simd.h"
 #endif
 
@@ -226,7 +223,7 @@
      */
     if (buf == Z_NULL) {
         if (!len) /* Assume user is calling crc32(0, NULL, 0); */
-            x86_check_features();
+            cpu_check_features();
         return 0UL;
     }
 
@@ -289,7 +286,7 @@
      */
     if (buf == Z_NULL) {
         if (!len) /* Assume user is calling crc32(0, NULL, 0); */
-            arm_check_features();
+            cpu_check_features();
         return 0UL;
     }
 
@@ -500,25 +497,31 @@
 
 ZLIB_INTERNAL void crc_reset(deflate_state *const s)
 {
+#ifdef ADLER32_SIMD_SSSE3
     if (x86_cpu_enable_simd) {
         crc_fold_init(s);
         return;
     }
+#endif
     s->strm->adler = crc32(0L, Z_NULL, 0);
 }
 
 ZLIB_INTERNAL void crc_finalize(deflate_state *const s)
 {
+#ifdef ADLER32_SIMD_SSSE3
     if (x86_cpu_enable_simd)
         s->strm->adler = crc_fold_512to32(s);
+#endif
 }
 
 ZLIB_INTERNAL void copy_with_crc(z_streamp strm, Bytef *dst, long size)
 {
+#ifdef ADLER32_SIMD_SSSE3
     if (x86_cpu_enable_simd) {
         crc_fold_copy(strm->state, dst, strm->next_in, size);
         return;
     }
+#endif
     zmemcpy(dst, strm->next_in, size);
     strm->adler = crc32(strm->adler, dst, size);
 }
diff --git a/third_party/zlib/deflate.c b/third_party/zlib/deflate.c
index 201254a..a39e627 100644
--- a/third_party/zlib/deflate.c
+++ b/third_party/zlib/deflate.c
@@ -50,7 +50,7 @@
 /* @(#) $Id$ */
 #include <assert.h>
 #include "deflate.h"
-#include "x86.h"
+#include "cpu_features.h"
 #include "contrib/optimizations/insert_string.h"
 
 #if (defined(__ARM_NEON__) || defined(__ARM_NEON))
@@ -244,10 +244,8 @@
     // for all wrapper formats (e.g. RAW, ZLIB, GZIP).
     // Feature detection is not triggered while using RAW mode (i.e. we never
     // call crc32() with a NULL buffer).
-#if defined(CRC32_ARMV8_CRC32)
-    arm_check_features();
-#elif defined(CRC32_SIMD_SSE42_PCLMUL)
-    x86_check_features();
+#if defined(CRC32_ARMV8_CRC32) || defined(CRC32_SIMD_SSE42_PCLMUL)
+    cpu_check_features();
 #endif
 
     if (version == Z_NULL || version[0] != my_version[0] ||
@@ -1519,11 +1517,12 @@
 
 local void fill_window(deflate_state *s)
 {
+#ifdef ADLER32_SIMD_SSSE3
     if (x86_cpu_enable_simd) {
         fill_window_sse(s);
         return;
     }
-
+#endif
     fill_window_c(s);
 }
 
diff --git a/third_party/zlib/simd_stub.c b/third_party/zlib/simd_stub.c
deleted file mode 100644
index c6d4605..0000000
--- a/third_party/zlib/simd_stub.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* simd_stub.c -- stub implementations
-* Copyright (C) 2014 Intel Corporation
-* For conditions of distribution and use, see copyright notice in zlib.h
-*/
-#include <assert.h>
-
-#include "deflate.h"
-#include "x86.h"
-
-int ZLIB_INTERNAL x86_cpu_enable_simd = 0;
-
-void ZLIB_INTERNAL crc_fold_init(deflate_state *const s) {
-    assert(0);
-}
-
-void ZLIB_INTERNAL crc_fold_copy(deflate_state *const s,
-                                 unsigned char *dst,
-                                 const unsigned char *src,
-                                 long len) {
-    assert(0);
-}
-
-unsigned ZLIB_INTERNAL crc_fold_512to32(deflate_state *const s) {
-    assert(0);
-    return 0;
-}
-
-void ZLIB_INTERNAL fill_window_sse(deflate_state *s)
-{
-    assert(0);
-}
-
-void x86_check_features(void)
-{
-}
diff --git a/third_party/zlib/x86.c b/third_party/zlib/x86.c
deleted file mode 100644
index 7488ad0..0000000
--- a/third_party/zlib/x86.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * x86 feature check
- *
- * Copyright (C) 2013 Intel Corporation. All rights reserved.
- * Author:
- *  Jim Kukunas
- *
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-#include "x86.h"
-#include "zutil.h"
-
-int ZLIB_INTERNAL x86_cpu_enable_ssse3 = 0;
-int ZLIB_INTERNAL x86_cpu_enable_simd = 0;
-
-#ifndef _MSC_VER
-#include <pthread.h>
-
-pthread_once_t cpu_check_inited_once = PTHREAD_ONCE_INIT;
-static void _x86_check_features(void);
-
-void x86_check_features(void)
-{
-  pthread_once(&cpu_check_inited_once, _x86_check_features);
-}
-
-static void _x86_check_features(void)
-{
-    int x86_cpu_has_sse2;
-    int x86_cpu_has_ssse3;
-    int x86_cpu_has_sse42;
-    int x86_cpu_has_pclmulqdq;
-    unsigned eax, ebx, ecx, edx;
-
-    eax = 1;
-#ifdef __i386__
-    __asm__ __volatile__ (
-        "xchg %%ebx, %1\n\t"
-        "cpuid\n\t"
-        "xchg %1, %%ebx\n\t"
-    : "+a" (eax), "=S" (ebx), "=c" (ecx), "=d" (edx)
-    );
-#else
-    __asm__ __volatile__ (
-        "cpuid\n\t"
-    : "+a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
-    );
-#endif  /* (__i386__) */
-
-    x86_cpu_has_sse2 = edx & 0x4000000;
-    x86_cpu_has_ssse3 = ecx & 0x000200;
-    x86_cpu_has_sse42 = ecx & 0x100000;
-    x86_cpu_has_pclmulqdq = ecx & 0x2;
-
-    x86_cpu_enable_ssse3 = x86_cpu_has_ssse3;
-
-    x86_cpu_enable_simd = x86_cpu_has_sse2 &&
-                          x86_cpu_has_sse42 &&
-                          x86_cpu_has_pclmulqdq;
-}
-#else
-#include <intrin.h>
-#include <windows.h>
-
-static BOOL CALLBACK _x86_check_features(PINIT_ONCE once,
-                                         PVOID param,
-                                         PVOID *context);
-static INIT_ONCE cpu_check_inited_once = INIT_ONCE_STATIC_INIT;
-
-void x86_check_features(void)
-{
-    InitOnceExecuteOnce(&cpu_check_inited_once, _x86_check_features,
-                        NULL, NULL);
-}
-
-static BOOL CALLBACK _x86_check_features(PINIT_ONCE once,
-                                         PVOID param,
-                                         PVOID *context)
-{
-    int x86_cpu_has_sse2;
-    int x86_cpu_has_ssse3;
-    int x86_cpu_has_sse42;
-    int x86_cpu_has_pclmulqdq;
-    int regs[4];
-
-    __cpuid(regs, 1);
-
-    x86_cpu_has_sse2 = regs[3] & 0x4000000;
-    x86_cpu_has_ssse3 = regs[2] & 0x000200;
-    x86_cpu_has_sse42 = regs[2] & 0x100000;
-    x86_cpu_has_pclmulqdq = regs[2] & 0x2;
-
-    x86_cpu_enable_ssse3 = x86_cpu_has_ssse3;
-
-    x86_cpu_enable_simd = x86_cpu_has_sse2 &&
-                          x86_cpu_has_sse42 &&
-                          x86_cpu_has_pclmulqdq;
-    return TRUE;
-}
-#endif  /* _MSC_VER */
diff --git a/third_party/zlib/x86.h b/third_party/zlib/x86.h
deleted file mode 100644
index 7205d50..0000000
--- a/third_party/zlib/x86.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* x86.h -- check for x86 CPU features
-* Copyright (C) 2013 Intel Corporation Jim Kukunas
-* For conditions of distribution and use, see copyright notice in zlib.h
-*/
-
-#ifndef X86_H
-#define X86_H
-
-#include "zlib.h"
-
-extern int x86_cpu_enable_ssse3;
-extern int x86_cpu_enable_simd;
-
-void x86_check_features(void);
-
-#endif  /* X86_H */
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index 08e1323..df4c632 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -225,6 +225,9 @@
   "components/sync/driver/resources.grd": {
     "includes": [2200],
   },
+  "components/resources/dev_ui_components_resources.grd": {
+    "includes": [2210],
+  },
   "content/browser/resources/media/media_internals_resources.grd": {
     "includes": [2220],
   },
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index b2f499b..4e1a99c 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -2485,6 +2485,13 @@
   <description>Please enter the description of this user action.</description>
 </action>
 
+<action name="AppList_SearchQueryStarted">
+  <owner>jennyz@chromium.org</owner>
+  <description>
+    User starts a new search query in launcher search box.
+  </description>
+</action>
+
 <action name="AppList_ShowPlayStoreQueryResults">
   <owner>jennyz@chromium.org</owner>
   <owner>newcomer@chromium.org</owner>
@@ -5692,6 +5699,13 @@
   </description>
 </action>
 
+<action name="DownloadNotification.Button_DeepScan">
+  <owner>drubery@chromium.org</owner>
+  <description>
+    User pushes &quot;Scan&quot; on the prompt for download deep scanning
+  </description>
+</action>
+
 <action name="DownloadNotification.Button_Discard">
   <owner>yoshiki@chromium.org</owner>
   <description>
@@ -13923,6 +13937,14 @@
   </description>
 </action>
 
+<action name="MobileToolbarStackViewNewIncognitoTab">
+  <owner>gogerald@chromium.org</owner>
+  <description>
+    The user taps the new tab button '+' on the tab switcher toolbar to create a
+    new incognito tab.
+  </description>
+</action>
+
 <action name="MobileToolbarStackViewNewTab">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 3588bc33..5c91d52 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -68473,6 +68473,24 @@
 </enum>
 
 <enum name="WinGetLastError">
+  <int value="-2146893818" label="NTE_BAD_SIGNATURE"/>
+  <int value="-2146893815" label="NTE_BAD_FLAGS"/>
+  <int value="-2146893813" label="NTE_BAD_KEY_STATE">
+    The user password has changed since the private keys were encrypted.
+  </int>
+  <int value="-2146893810" label="NTE_NO_MEMORY"/>
+  <int value="-2146893809" label="NTE_EXISTS"/>
+  <int value="-2146893804" label="NTE_BAD_PROV_TYPE"/>
+  <int value="-2146893802" label="NTE_BAD_KEYSET"/>
+  <int value="-2146893801" label="NTE_PROV_TYPE_NOT_DEF"/>
+  <int value="-2146893800" label="NTE_PROV_TYPE_ENTRY_BAD"/>
+  <int value="-2146893799" label="NTE_KEYSET_NOT_DEF"/>
+  <int value="-2146893798" label="NTE_KEYSET_ENTRY_BAD"/>
+  <int value="-2146893797" label="NTE_PROV_TYPE_NO_MATCH"/>
+  <int value="-2146893796" label="NTE_SIGNATURE_FILE_BAD"/>
+  <int value="-2146893795" label="NTE_PROVIDER_DLL_FAIL"/>
+  <int value="-2146893794" label="NTE_PROV_DLL_NOT_FOUND"/>
+  <int value="-2146893793" label="NTE_BAD_KEYSET_PARAM"/>
   <int value="0" label="SUCCESS"/>
   <int value="1" label="INVALID_FUNCTION"/>
   <int value="2" label="FILE_NOT_FOUND"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index a55aebd..e2019a1 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -567,7 +567,7 @@
 </histogram>
 
 <histogram base="true" name="Accessibility.ScreenReader.Image.SizeRatio"
-    units="%" expires_after="M80">
+    units="%" expires_after="2020-05-10">
 <!-- Name completed by histogram_suffixes
        name="AccessibilityScreenReaderImage" -->
 
@@ -25425,7 +25425,7 @@
 </histogram>
 
 <histogram name="ContentSettings.PermissionRequested" enum="PermissionType"
-    expires_after="2020-06-28">
+    expires_after="M90">
   <owner>dominickn@chromium.org</owner>
   <owner>engedy@chromium.org</owner>
   <owner>hkamila@chromium.org</owner>
@@ -38190,7 +38190,7 @@
 </histogram>
 
 <histogram name="Download.DownloadManager.CreationDelay" units="ms"
-    expires_after="2020-06-28">
+    expires_after="M83">
   <owner>qinmin@chromium.org</owner>
   <owner>dtrainor@chromium.org</owner>
   <summary>
@@ -38200,7 +38200,7 @@
 </histogram>
 
 <histogram name="Download.DownloadManager.MemoryUsage" units="KB"
-    expires_after="2020-06-28">
+    expires_after="M83">
   <owner>qinmin@chromium.org</owner>
   <owner>dtrainor@chromium.org</owner>
   <summary>
@@ -38358,7 +38358,7 @@
 </histogram>
 
 <histogram name="Download.InProgressDB.Counts"
-    enum="DownloadInProgressDBCountType" expires_after="M81">
+    enum="DownloadInProgressDBCountType" expires_after="M83">
   <owner>qinmin@chromium.org</owner>
   <summary>
     Various individual counts related to in-progress download DB.
@@ -97617,6 +97617,9 @@
 
 <histogram name="NQE.ContentObserver.NetworkQualityMeaningfullyChanged"
     enum="BooleanChanged" expires_after="M81">
+  <obsolete>
+    Obsoleted in M81.
+  </obsolete>
   <owner>tbansal@chromium.org</owner>
   <summary>
     This metric is recorded when the network quality change notification is
@@ -98250,6 +98253,9 @@
 
 <histogram name="NQE.WifiSignalStrength.LevelDifference"
     units="Signal Strength Level" expires_after="2020-02-16">
+  <obsolete>
+    Obsoleted in M81.
+  </obsolete>
   <owner>tbansal@chromium.org</owner>
   <owner>bengr@chromium.org</owner>
   <summary>
@@ -102684,6 +102690,17 @@
   </summary>
 </histogram>
 
+<histogram name="OSCrypt.Win.MasterKeyDecryptionError" enum="WinGetLastError"
+    expires_after="2021-01-01">
+  <owner>wfh@chromium.org</owner>
+  <owner>forshaw@chromium.org</owner>
+  <summary>
+    The Windows GetLastError after a failure from calling into DPAPI to decrypt
+    the master key for the os_crypt library on Windows. This is recorded during
+    the OSCrypt::Init each time the decryption fails.
+  </summary>
+</histogram>
+
 <histogram name="OSX.BluetoothAvailability" enum="BluetoothAvailability"
     expires_after="2018-08-30">
   <obsolete>
@@ -104878,6 +104895,9 @@
 <histogram
     name="PageLoad.Clients.ThirdParty.Frames.NavigationToFirstContentfulPaint"
     units="ms" expires_after="2021-11-01">
+  <obsolete>
+    Deprecated in December 2010.
+  </obsolete>
   <owner>jkarlin@chromium.org</owner>
   <owner>johnidel@chromium.org</owner>
   <summary>
@@ -104887,6 +104907,18 @@
   </summary>
 </histogram>
 
+<histogram
+    name="PageLoad.Clients.ThirdParty.Frames.NavigationToFirstContentfulPaint2"
+    units="ms" expires_after="2020-12-04">
+  <owner>jkarlin@chromium.org</owner>
+  <owner>johnidel@chromium.org</owner>
+  <summary>
+    The time from navigation start to the first contentful paint of third-party
+    (third party in respect to eTLD+1) frames on pages. Note that this can be
+    significantly delayed due to lazy loading.
+  </summary>
+</histogram>
+
 <histogram name="PageLoad.Clients.ThirdParty.Origins.CookieRead" units="Count"
     expires_after="2021-07-01">
   <owner>jkarlin@chromium.org</owner>
@@ -111479,6 +111511,9 @@
 <histogram
     name="PerformanceManager.BrowsingInstancePluralityVisibilityState.ByPageTime"
     enum="BrowsingInstancePluralityVisibilityState" expires_after="2019-09-30">
+  <obsolete>
+    Removed 2020-01-06 as this was only added for a brief exploration.
+  </obsolete>
   <owner>chrisha@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -111493,6 +111528,9 @@
 <histogram
     name="PerformanceManager.BrowsingInstancePluralityVisibilityState.ByTime"
     enum="BrowsingInstancePluralityVisibilityState" expires_after="2019-09-30">
+  <obsolete>
+    Removed 2020-01-06 as this was only added for a brief exploration.
+  </obsolete>
   <owner>chrisha@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -111521,7 +111559,7 @@
 
 <histogram
     name="PerformanceManager.FrameSiteInstanceProcessRelationship.ByProcess2"
-    enum="FrameSiteInstanceProcessRelationship" expires_after="2019-09-30">
+    enum="FrameSiteInstanceProcessRelationship" expires_after="2020-12-31">
   <owner>chrisha@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -111550,7 +111588,7 @@
 
 <histogram
     name="PerformanceManager.FrameSiteInstanceProcessRelationship.ByTime2"
-    enum="FrameSiteInstanceProcessRelationship" expires_after="2019-09-30">
+    enum="FrameSiteInstanceProcessRelationship" expires_after="2020-12-31">
   <owner>chrisha@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -111561,7 +111599,7 @@
 </histogram>
 
 <histogram name="PerformanceManager.FramesPerRendererByTime" units="units"
-    expires_after="2019-09-30">
+    expires_after="2020-12-31">
   <owner>chrisha@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -111572,7 +111610,7 @@
 </histogram>
 
 <histogram name="PerformanceManager.SiteInstancesPerRendererByTime"
-    units="units" expires_after="2019-09-30">
+    units="units" expires_after="2020-12-31">
   <owner>chrisha@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
diff --git a/tools/perf/core/perf_benchmark.py b/tools/perf/core/perf_benchmark.py
index 52cba20..abd0f0d 100644
--- a/tools/perf/core/perf_benchmark.py
+++ b/tools/perf/core/perf_benchmark.py
@@ -112,13 +112,6 @@
     browser_options.AppendExtraBrowserArgs(
         '--disable-gpu-process-for-dx12-vulkan-info-collection')
 
-    # TODO(crbug.com/881469): remove this once Webview supports
-    # VizDisplayCompositor.
-    if (browser_options.browser_type and
-        'android-webview' in browser_options.browser_type):
-      browser_options.AppendExtraBrowserArgs(
-          '--disable-features=VizDisplayCompositor')
-
     self.SetExtraBrowserOptions(browser_options)
 
   def GetExtraOutDirectories(self):
diff --git a/ui/android/delegated_frame_host_android.cc b/ui/android/delegated_frame_host_android.cc
index 6b27b06..5f3537a1 100644
--- a/ui/android/delegated_frame_host_android.cc
+++ b/ui/android/delegated_frame_host_android.cc
@@ -11,7 +11,6 @@
 #include "cc/layers/surface_layer.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/swap_promise.h"
-#include "components/viz/common/features.h"
 #include "components/viz/common/frame_sinks/copy_output_result.h"
 #include "components/viz/common/quads/compositor_frame.h"
 #include "components/viz/common/surfaces/surface_id.h"
@@ -82,7 +81,6 @@
       frame_evictor_(std::make_unique<viz::FrameEvictor>(this)) {
   DCHECK(view_);
   DCHECK(client_);
-  DCHECK(features::IsVizDisplayCompositorEnabled());
 
   constexpr bool is_transparent = false;
   content_layer_ = CreateSurfaceLayer(
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js b/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js
index 7871acf..81b8ff1 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js
+++ b/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js
@@ -167,9 +167,13 @@
       let ipv6 = this.getIPConfigUIProperties_(
           OncMojo.getIPConfigForType(properties, 'IPv6'));
 
-      // If ipv6 address is not set, show appropriate message.
-      ipv6 = ipv6 || {};
-      ipv6.ipAddress = ipv6.ipAddress || this.i18n('ipAddressNotAvailable');
+      // If connected and the IP address is automatic and set, show message if
+      // the ipv6 address is not set.
+      if (OncMojo.connectionStateIsConnected(properties.connectionState) &&
+          this.automatic_ && ipv4 && ipv4.ipAddress) {
+        ipv6 = ipv6 || {};
+        ipv6.ipAddress = ipv6.ipAddress || this.i18n('ipAddressNotAvailable');
+      }
 
       this.ipConfig_ = {ipv4: ipv4, ipv6: ipv6};
     } else {
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/RemoteFragmentImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/RemoteFragmentImpl.java
index 3dc3a0b..5a30204e 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/RemoteFragmentImpl.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/RemoteFragmentImpl.java
@@ -129,7 +129,7 @@
         }
     }
 
-    public void onSaveInstaceState(Bundle outState) {
+    public void onSaveInstanceState(Bundle outState) {
         try {
             mClient.superOnSaveInstanceState(ObjectWrapper.wrap(outState));
         } catch (RemoteException e) {
@@ -244,7 +244,7 @@
     @Override
     public final void handleOnSaveInstanceState(IObjectWrapper outState) {
         StrictModeWorkaround.apply();
-        onSaveInstaceState(ObjectWrapper.unwrap(outState, Bundle.class));
+        onSaveInstanceState(ObjectWrapper.unwrap(outState, Bundle.class));
     }
 
     @Override